[PATCH 4.7 30/31] tpm: fix a race condition in tpm2_unseal_trusted()

2016-10-14 Thread Greg Kroah-Hartman
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 

[PATCH 4.7 30/31] tpm: fix a race condition in tpm2_unseal_trusted()

2016-10-14 Thread Greg Kroah-Hartman
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 =