KEYS: trusted: Reserve TPM for seal and unseal operations
authorJarkko Sakkinen <jarkko@kernel.org>
Thu, 28 Jan 2021 23:56:21 +0000 (01:56 +0200)
committerJarkko Sakkinen <jarkko@kernel.org>
Tue, 16 Feb 2021 08:40:28 +0000 (10:40 +0200)
When TPM 2.0 trusted keys code was moved to the trusted keys subsystem,
the operations were unwrapped from tpm_try_get_ops() and tpm_put_ops(),
which are used to take temporarily the ownership of the TPM chip. The
ownership is only taken inside tpm_send(), but this is not sufficient,
as in the key load TPM2_CC_LOAD, TPM2_CC_UNSEAL and TPM2_FLUSH_CONTEXT
need to be done as a one single atom.

Take the TPM chip ownership before sending anything with
tpm_try_get_ops() and tpm_put_ops(), and use tpm_transmit_cmd() to send
TPM commands instead of tpm_send(), reverting back to the old behaviour.

Fixes: 2e19e10131a0 ("KEYS: trusted: Move TPM2 trusted keys code")
Reported-by: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: stable@vger.kernel.org
Cc: David Howells <dhowells@redhat.com>
Cc: Mimi Zohar <zohar@linux.ibm.com>
Cc: Sumit Garg <sumit.garg@linaro.org>
Acked-by Sumit Garg <sumit.garg@linaro.org>
Tested-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
drivers/char/tpm/tpm.h
include/linux/tpm.h
security/keys/trusted-keys/trusted_tpm2.c

index 947d1db0a5ccf756172cfb9275ed9e046d4cdd38..283f78211c3a7bc09092085d12834c48571f93f3 100644 (file)
@@ -164,8 +164,6 @@ extern const struct file_operations tpmrm_fops;
 extern struct idr dev_nums_idr;
 
 ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz);
-ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
-                        size_t min_rsp_body_length, const char *desc);
 int tpm_get_timeouts(struct tpm_chip *);
 int tpm_auto_startup(struct tpm_chip *chip);
 
@@ -194,8 +192,6 @@ static inline void tpm_msleep(unsigned int delay_msec)
 int tpm_chip_start(struct tpm_chip *chip);
 void tpm_chip_stop(struct tpm_chip *chip);
 struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
-__must_check int tpm_try_get_ops(struct tpm_chip *chip);
-void tpm_put_ops(struct tpm_chip *chip);
 
 struct tpm_chip *tpm_chip_alloc(struct device *dev,
                                const struct tpm_class_ops *ops);
index ae2482510f8c82478700a841d57cc74b1a4fbb8a..543aa3b1dedc0766fe52b956b3149e724f51bdaf 100644 (file)
@@ -404,6 +404,10 @@ static inline u32 tpm2_rc_value(u32 rc)
 #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
 
 extern int tpm_is_tpm2(struct tpm_chip *chip);
+extern __must_check int tpm_try_get_ops(struct tpm_chip *chip);
+extern void tpm_put_ops(struct tpm_chip *chip);
+extern ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
+                               size_t min_rsp_body_length, const char *desc);
 extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
                        struct tpm_digest *digest);
 extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
@@ -417,7 +421,6 @@ static inline int tpm_is_tpm2(struct tpm_chip *chip)
 {
        return -ENODEV;
 }
-
 static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx,
                               struct tpm_digest *digest)
 {
index 08ec7f48f01d09d643f2f0b69021686a88adad7e..e2a0ed5d02f013392d337a1b543eeda1e986ba74 100644 (file)
@@ -83,6 +83,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
        if (rc)
                return rc;
 
+       rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
+       if (rc) {
+               tpm_put_ops(chip);
+               return rc;
+       }
+
        tpm_buf_append_u32(&buf, options->keyhandle);
        tpm2_buf_append_auth(&buf, TPM2_RS_PW,
                             NULL /* nonce */, 0,
@@ -130,7 +136,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
                goto out;
        }
 
-       rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
+       rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
        if (rc)
                goto out;
 
@@ -157,6 +163,7 @@ out:
                        rc = -EPERM;
        }
 
+       tpm_put_ops(chip);
        return rc;
 }
 
@@ -211,7 +218,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
                goto out;
        }
 
-       rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
+       rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
        if (!rc)
                *blob_handle = be32_to_cpup(
                        (__be32 *) &buf.data[TPM_HEADER_SIZE]);
@@ -260,7 +267,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
                             options->blobauth /* hmac */,
                             TPM_DIGEST_SIZE);
 
-       rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
+       rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
        if (rc > 0)
                rc = -EPERM;
 
@@ -304,12 +311,19 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
        u32 blob_handle;
        int rc;
 
-       rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
+       rc = tpm_try_get_ops(chip);
        if (rc)
                return rc;
 
+       rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
+       if (rc)
+               goto out;
+
        rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
        tpm2_flush_context(chip, blob_handle);
 
+out:
+       tpm_put_ops(chip);
+
        return rc;
 }