If clk_enable is not defined and chip initialization
is canceled code hits null dereference.

Easily reproducible with vTPM init fail:
  swtpm chardev --tpmstate dir=nonexistent_dir --tpm2 --vtpm-proxy

BUG: kernel NULL pointer dereference, address: 00000000
...
Call Trace:
 tpm_chip_start+0x9d/0xa0 [tpm]
 tpm_chip_register+0x10/0x1a0 [tpm]
 vtpm_proxy_work+0x11/0x30 [tpm_vtpm_proxy]
 process_one_work+0x214/0x5a0
 worker_thread+0x134/0x3e0
 ? process_one_work+0x5a0/0x5a0
 kthread+0xd4/0x100
 ? process_one_work+0x5a0/0x5a0
 ? kthread_park+0x90/0x90
 ret_from_fork+0x19/0x24

Fixes: 719b7d81f204 ("tpm: introduce tpm_chip_start() and tpm_chip_stop()")
Cc: sta...@vger.kernel.org # v5.1+
Signed-off-by: Milan Broz <gmazyl...@gmail.com>
---
 drivers/char/tpm/tpm-chip.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 90325e1749fb..db6ac6f83948 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -77,6 +77,18 @@ static int tpm_go_idle(struct tpm_chip *chip)
        return chip->ops->go_idle(chip);
 }
 
+static void tpm_clk_enable(struct tpm_chip *chip)
+{
+       if (chip->ops->clk_enable)
+               chip->ops->clk_enable(chip, true);
+}
+
+static void tpm_clk_disable(struct tpm_chip *chip)
+{
+       if (chip->ops->clk_enable)
+               chip->ops->clk_enable(chip, false);
+}
+
 /**
  * tpm_chip_start() - power on the TPM
  * @chip:      a TPM chip to use
@@ -89,13 +101,12 @@ int tpm_chip_start(struct tpm_chip *chip)
 {
        int ret;
 
-       if (chip->ops->clk_enable)
-               chip->ops->clk_enable(chip, true);
+       tpm_clk_enable(chip);
 
        if (chip->locality == -1) {
                ret = tpm_request_locality(chip);
                if (ret) {
-                       chip->ops->clk_enable(chip, false);
+                       tpm_clk_disable(chip);
                        return ret;
                }
        }
@@ -103,8 +114,7 @@ int tpm_chip_start(struct tpm_chip *chip)
        ret = tpm_cmd_ready(chip);
        if (ret) {
                tpm_relinquish_locality(chip);
-               if (chip->ops->clk_enable)
-                       chip->ops->clk_enable(chip, false);
+               tpm_clk_disable(chip);
                return ret;
        }
 
@@ -124,8 +134,7 @@ void tpm_chip_stop(struct tpm_chip *chip)
 {
        tpm_go_idle(chip);
        tpm_relinquish_locality(chip);
-       if (chip->ops->clk_enable)
-               chip->ops->clk_enable(chip, false);
+       tpm_clk_disable(chip);
 }
 EXPORT_SYMBOL_GPL(tpm_chip_stop);
 
-- 
2.20.1

Reply via email to