tpm: Actually fail on TPM errors during "get random"
Subsystems (2)
PATCH 1/1 tpm: Actually fail on TPM errors during "get random"
A "get random" may fail with a TPM error, but those codes were returned as-is to the caller, which assumed the result was the number of bytes that had been written to the target buffer, which could lead to an kernel heap memory exposure and over-read.
This fixes tpm1_get_random() to mask positive TPM errors into -EIO, as before.
[ 18.092103] tpm tpm0: A TPM error (379) occurred attempting get random [ 18.092106] usercopy: Kernel memory exposure attempt detected from SLUB object 'kmalloc-64' (offset 0, size 379)!
--- drivers/char/tpm/tpm1-cmd.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/char/tpm/tpm1-cmd.c +6 -3
@@ -510,7 +510,7 @@ struct tpm1_get_random_out {* * Return: * * number of bytes read -* * -errno or a TPM return code otherwise +* * -errno (positive TPM return codes are masked to -EIO) */ int tpm1_get_random (struct tpm_chip *chip,u8 *dest,size_t max) {
@@ -524,7 +524,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc =tpm_buf_init (&buf,TPM_TAG_RQU_COMMAND ,TPM_ORD_GET_RANDOM );if (rc) -return rc; + goto fail; do { tpm_buf_append_u32(&buf, num_bytes);
@@ -559,7 +559,10 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc = total ? (int )total : -EIO ; out:tpm_buf_destroy (&buf); -return rc; +fail: +if (rc <0 ) +return rc; +return -EIO ; }#define TPM_ORD_PCRREAD 21
Signature · 5 lines
2.17.1 -- Kees Cook
Jason Gunthorpe
reviewerQuoted 36 lines · Kees Cook
A "get random" may fail with a TPM error, but those codes were returned as-is to the caller, which assumed the result was the number of bytes that had been written to the target buffer, which could lead to an kernel heap memory exposure and over-read.
This fixes
tpm1_get_random()to mask positive TPM errors into-EIO, as before.[ 18.092103] tpm tpm0: A TPM error (379) occurred attempting get random [ 18.092106] usercopy: Kernel memory exposure attempt detected from SLUB object 'kmalloc-64' (offset 0, size 379)!Reported-by Phil Baker <[email protected]>Reported-by Craig Robson <[email protected]>Fixes 7aee9c52d7ac ("tpm: tpm1: rewrite tpm1_get_random() using tpm_buf structure")Cc Laura Abbott <[email protected]>Cc Tomas Winkler <[email protected]>Cc Jarkko Sakkinen <[email protected]>Signed-off-by Kees Cook <[email protected]>drivers/char/tpm/tpm1-cmd.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)drivers/char/tpm/tpm1-cmd.c +2
-1+++ b/drivers/char/tpm/tpm1-cmd.c@@ -510,7 +510,7 @@ struct tpm1_get_random_out {* * Return: * * number of bytes read -* * -errno or a TPM return code otherwise +* * -errno (positive TPM return codes are masked to -EIO) */ int tpm1_get_random (struct tpm_chip *chip,u8 *dest,size_t max) {
drivers/char/tpm/tpm1-cmd.c int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) · line 527
Quoted 5 lines
drivers/char/tpm/tpm1-cmd.c +1
-1@@ -524,7 +524,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc =tpm_buf_init (&buf,TPM_TAG_RQU_COMMAND ,TPM_ORD_GET_RANDOM );if (rc) -return rc; + goto fail;
?? Does tpm_buf_init() return positive?? Shouldn't..
I think you actually want this:
drivers/char/tpm/tpm1-cmd.c +4 -2
@@ -510,7 +510,7 @@ struct tpm1_get_random_out {* * Return: * * number of bytes read -* * -errno or a TPM return code otherwise +* * -errno */ int tpm1_get_random (struct tpm_chip *chip,u8 *dest,size_t max) {
@@ -531,8 +531,10 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc =tpm_transmit_cmd (chip, &buf,sizeof (out->rng_data_len),"attempting get random" ); -if (rc) +if (rc) { + rc = -EIO goto out; + } out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE ];
drivers/char/tpm/tpm2-cmd.c +3 -1
@@ -328,8 +328,10 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) offsetof(struct tpm2_get_random_out , buffer), "attempting get random"); -if (err) +if (err) { + rc = -EIO ; goto out; + } out = (struct tpm2_get_random_out *) &buf.data[TPM_HEADER_SIZE ];
Quoted 39 lines · Jason Gunthorpe
Quoted 37 lines · Kees Cook
A "get random" may fail with a TPM error, but those codes were returned as-is to the caller, which assumed the result was the number of bytes that had been written to the target buffer, which could lead to an kernel heap memory exposure and over-read.
This fixes
tpm1_get_random()to mask positive TPM errors into-EIO, as before.[ 18.092103] tpm tpm0: A TPM error (379) occurred attempting get random [ 18.092106] usercopy: Kernel memory exposure attempt detected from SLUB object 'kmalloc-64' (offset 0, size 379)!Reported-by Phil Baker <[email protected]>Reported-by Craig Robson <[email protected]>Fixes 7aee9c52d7ac ("tpm: tpm1: rewrite tpm1_get_random() using tpm_buf structure")Cc Laura Abbott <[email protected]>Cc Tomas Winkler <[email protected]>Cc Jarkko Sakkinen <[email protected]>Signed-off-by Kees Cook <[email protected]>drivers/char/tpm/tpm1-cmd.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)drivers/char/tpm/tpm1-cmd.c +2
-1+++ b/drivers/char/tpm/tpm1-cmd.c@@ -510,7 +510,7 @@ struct tpm1_get_random_out {* * Return: * * number of bytes read -* * -errno or a TPM return code otherwise +* * -errno (positive TPM return codes are masked to -EIO) */ int tpm1_get_random (struct tpm_chip *chip,u8 *dest,size_t max) {@@ -524,7 +524,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
Quoted 8 lines
drivers/char/tpm/tpm1-cmd.c int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) · line 527
Quoted 4 lines
drivers/char/tpm/tpm1-cmd.c +1
-1rc =tpm_buf_init (&buf,TPM_TAG_RQU_COMMAND ,TPM_ORD_GET_RANDOM );if (rc) -return rc; + goto fail;?? Does
tpm_buf_init()return positive?? Shouldn't..I think you actually want this:
I didn't check that, but it was tpm_transmit_cmd() that was failing (and would be covered by the error path change I sent).
Quoted 32 lines
drivers/char/tpm/tpm1-cmd.c +4
-2@@ -510,7 +510,7 @@ struct tpm1_get_random_out {* * Return: * * number of bytes read -* * -errno or a TPM return code otherwise +* * -errno */ int tpm1_get_random (struct tpm_chip *chip,u8 *dest,size_t max) {@@ -531,8 +531,10 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc =tpm_transmit_cmd (chip, &buf,sizeof (out->rng_data_len),"attempting get random" ); -if (rc) +if (rc) { + rc = -EIO goto out; + } out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE ];drivers/char/tpm/tpm2-cmd.c +0
-0@@ -328,8 +328,10 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) offsetof(struct tpm2_get_random_out,
drivers/char/tpm/tpm2-cmd.c int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) · line 337
Quoted 10 lines
drivers/char/tpm/tpm2-cmd.c +3
-1buffer), "attempting get random"); -if (err) +if (err) { + rc = -EIO ; goto out; + } out = (struct tpm2_get_random_out *) &buf.data[TPM_HEADER_SIZE ];
Eeks, I missed tpm2. In both cases, though a negative error would be masked. I was trying to leave those as-is and only mask positive errors.
Signature · 1 line
Kees Cook
James Bottomley
maintainerOn Mon, 2019-04-01 at 11:32 -0700, Kees Cook wrote:
[...]
Quoted 23 lines
drivers/char/tpm/tpm1-cmd.c +2
-2@@ -510,7 +510,7 @@ struct tpm1_get_random_out {* * Return: * * number of bytes read -* * -errno or a TPM return code otherwise +* * -errno (positive TPM return codes are masked to -EIO) */ int tpm1_get_random (struct tpm_chip *chip,u8 *dest,size_t max) {@@ -524,7 +524,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc =tpm_buf_init (&buf,TPM_TAG_RQU_COMMAND ,TPM_ORD_GET_RANDOM );if (rc) -return rc; + goto fail;drivers/char/tpm/tpm1-cmd.c +0
-0do { tpm_buf_append_u32(&buf, num_bytes);
drivers/char/tpm/tpm1-cmd.c int tpm1_get_random(struct tpm_chip *chip, u8 · line 563
Quoted 5 lines
drivers/char/tpm/tpm1-cmd.c +0
-1@@ -559,7 +559,10 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc = total ? (int )total : -EIO ; out:tpm_buf_destroy (&buf); -return rc;
You can't remove this otherwise the only return will ever be a failure.
I think what you're trying to catch is tpm_transmit_cmd returning a positive failure, So you need to check the output of tpm_transmit_cmd as well and goto failure leaving the above return in place.
James
Quoted 11 lines
drivers/char/tpm/tpm1-cmd.c +4
-0+fail: +if (rc <0 ) +return rc; +return -EIO ; }#define
TPM_ORD_PCRREAD21Signature · 1 line
2.17.1
Quoted 34 lines · James Bottomley
On Mon, 2019-04-01 at 11:32 -0700, Kees Cook wrote:
[...]Quoted 23 lines
drivers/char/tpm/tpm1-cmd.c +2
-2@@ -510,7 +510,7 @@ struct tpm1_get_random_out {* * Return: * * number of bytes read -* * -errno or a TPM return code otherwise +* * -errno (positive TPM return codes are masked to -EIO) */ int tpm1_get_random (struct tpm_chip *chip,u8 *dest,size_t max) {@@ -524,7 +524,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc =tpm_buf_init (&buf,TPM_TAG_RQU_COMMAND ,TPM_ORD_GET_RANDOM );if (rc) -return rc; + goto fail;do { tpm_buf_append_u32(&buf, num_bytes);drivers/char/tpm/tpm1-cmd.c int tpm1_get_random(struct tpm_chip *chip, u8 · line 563
Quoted 5 lines
drivers/char/tpm/tpm1-cmd.c +0
-1@@ -559,7 +559,10 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) rc = total ? (int )total : -EIO ; out:tpm_buf_destroy (&buf); -return rc;You can't remove this otherwise the only return will ever be a failure.
Quoted 3 lines
I think what you're trying to catch is
tpm_transmit_cmdreturning a positive failure, So you need to check the output oftpm_transmit_cmdas well and goto failure leaving the above return in place.
eek, yes. I double-checked this in tpm2, but tpm1 is different...
Signature · 1 line
Kees Cook