[PATCH 4.7 30/31] tpm: fix a race condition in tpm2_unseal_trusted()
4.7-stable review patch. If anyone has any objections, please let me know. -- From: Jarkko Sakkinencommit d4816edfe706497a8525480c1685ceb9871bc118 upstream. Unseal and load operations should be done as an atomic operation. This commit introduces unlocked tpm_transmit() so that tpm2_unseal_trusted() can do the locking by itself. Fixes: 0fe5480303a1 ("keys, trusted: seal/unseal with TPM 2.0 chips") Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-dev.c |2 drivers/char/tpm/tpm-interface.c | 51 ++- drivers/char/tpm/tpm-sysfs.c |2 drivers/char/tpm/tpm.h | 12 +++- drivers/char/tpm/tpm2-cmd.c | 101 +-- 5 files changed, 103 insertions(+), 65 deletions(-) --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -139,7 +139,7 @@ static ssize_t tpm_write(struct file *fi /* atomic tpm command send and result receive */ out_size = tpm_transmit(priv->chip, priv->data_buffer, - sizeof(priv->data_buffer)); + sizeof(priv->data_buffer), 0); if (out_size < 0) { mutex_unlock(>buffer_mutex); return out_size; --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -330,8 +330,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_durat /* * Internal kernel interface to transmit TPM commands */ -ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, -size_t bufsiz) +ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, +unsigned int flags) { ssize_t rc; u32 count, ordinal; @@ -350,7 +350,8 @@ ssize_t tpm_transmit(struct tpm_chip *ch return -E2BIG; } - mutex_lock(>tpm_mutex); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) + mutex_lock(>tpm_mutex); rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { @@ -393,20 +394,21 @@ out_recv: dev_err(chip->pdev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: - mutex_unlock(>tpm_mutex); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) + mutex_unlock(>tpm_mutex); return rc; } #define TPM_DIGEST_SIZE 20 #define TPM_RET_CODE_IDX 6 -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, -int len, const char *desc) +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, +int len, unsigned int flags, const char *desc) { - struct tpm_output_header *header; + const struct tpm_output_header *header; int err; - len = tpm_transmit(chip, (u8 *) cmd, len); + len = tpm_transmit(chip, (const u8 *)cmd, len, flags); if (len < 0) return len; else if (len < TPM_HEADER_SIZE) @@ -454,7 +456,8 @@ ssize_t tpm_getcap(struct device *dev, _ tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = subcap_id; } - rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, desc); + rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, + desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -470,7 +473,7 @@ void tpm_gen_interrupt(struct tpm_chip * tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); @@ -491,7 +494,7 @@ static int tpm_startup(struct tpm_chip * start_cmd.header.in = tpm_startup_header; start_cmd.params.startup_in.startup_type = startup_type; - return tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, + return tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, "attempting to start the TPM"); } @@ -522,7 +525,8 @@ int tpm_get_timeouts(struct tpm_chip *ch tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, + NULL); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to
[PATCH 4.7 30/31] tpm: fix a race condition in tpm2_unseal_trusted()
4.7-stable review patch. If anyone has any objections, please let me know. -- From: Jarkko Sakkinen commit d4816edfe706497a8525480c1685ceb9871bc118 upstream. Unseal and load operations should be done as an atomic operation. This commit introduces unlocked tpm_transmit() so that tpm2_unseal_trusted() can do the locking by itself. Fixes: 0fe5480303a1 ("keys, trusted: seal/unseal with TPM 2.0 chips") Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-dev.c |2 drivers/char/tpm/tpm-interface.c | 51 ++- drivers/char/tpm/tpm-sysfs.c |2 drivers/char/tpm/tpm.h | 12 +++- drivers/char/tpm/tpm2-cmd.c | 101 +-- 5 files changed, 103 insertions(+), 65 deletions(-) --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -139,7 +139,7 @@ static ssize_t tpm_write(struct file *fi /* atomic tpm command send and result receive */ out_size = tpm_transmit(priv->chip, priv->data_buffer, - sizeof(priv->data_buffer)); + sizeof(priv->data_buffer), 0); if (out_size < 0) { mutex_unlock(>buffer_mutex); return out_size; --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -330,8 +330,8 @@ EXPORT_SYMBOL_GPL(tpm_calc_ordinal_durat /* * Internal kernel interface to transmit TPM commands */ -ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, -size_t bufsiz) +ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, +unsigned int flags) { ssize_t rc; u32 count, ordinal; @@ -350,7 +350,8 @@ ssize_t tpm_transmit(struct tpm_chip *ch return -E2BIG; } - mutex_lock(>tpm_mutex); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) + mutex_lock(>tpm_mutex); rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { @@ -393,20 +394,21 @@ out_recv: dev_err(chip->pdev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: - mutex_unlock(>tpm_mutex); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) + mutex_unlock(>tpm_mutex); return rc; } #define TPM_DIGEST_SIZE 20 #define TPM_RET_CODE_IDX 6 -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, -int len, const char *desc) +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, +int len, unsigned int flags, const char *desc) { - struct tpm_output_header *header; + const struct tpm_output_header *header; int err; - len = tpm_transmit(chip, (u8 *) cmd, len); + len = tpm_transmit(chip, (const u8 *)cmd, len, flags); if (len < 0) return len; else if (len < TPM_HEADER_SIZE) @@ -454,7 +456,8 @@ ssize_t tpm_getcap(struct device *dev, _ tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = subcap_id; } - rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, desc); + rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, + desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -470,7 +473,7 @@ void tpm_gen_interrupt(struct tpm_chip * tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); @@ -491,7 +494,7 @@ static int tpm_startup(struct tpm_chip * start_cmd.header.in = tpm_startup_header; start_cmd.params.startup_in.startup_type = startup_type; - return tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, + return tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, "attempting to start the TPM"); } @@ -522,7 +525,8 @@ int tpm_get_timeouts(struct tpm_chip *ch tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, _cmd, TPM_INTERNAL_RESULT_SIZE, 0, + NULL); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. @@ -536,7 +540,7 @@ int tpm_get_timeouts(struct tpm_chip *ch tpm_cmd.params.getcap_in.subcap_size =