The length of a TPM reply is set by the device: tpm_sendrecv_command()
stores the number of bytes received, caps it only at the command buffer
size, and reports success whenever the reply's return code is 0. Callers
then use that length without checking it:
tpm2_get_capability() copies response_len - 15 bytes into the caller's
buffer. A reply shorter than 15 bytes underflows the subtraction into a
huge memcpy; a reply longer than the buffer (sized for prop_count
properties) overruns it.
tpm1_load_key2_oiap() and tpm1_get_pub_key_oiap() pass response_length
- 41 to verify_response_auth(), which a reply shorter than 41 bytes
underflows.
A TPM sits on a discrete SPI/I2C/LPC bus that is physically accessible, so
a reply this malformed is reachable by a bus interposer or a faulty part;
on the TPM2 path this parsing runs during measured boot.
Check the reported length against the header before the subtraction, and
against the caller's buffer before the GetCapability copy.
Fixes: 69cd8f0681f4 ("tpm: add TPM2_GetCapability command support")
Fixes: be6c1529c1ce ("tpm: add AUTH1 cmds for LoadKey2 and GetPubKey")
Signed-off-by: Shahriyar Jalayeri <[email protected]>
Acked-by: Miquel Raynal <[email protected]>
---
lib/tpm-v1.c | 6 ++++++
lib/tpm-v2.c | 8 ++++++++
2 files changed, 14 insertions(+)
diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c
index a6727c575fd..5fd22924b28 100644
--- a/lib/tpm-v1.c
+++ b/lib/tpm-v1.c
@@ -757,6 +757,9 @@ u32 tpm1_load_key2_oiap(struct udevice *dev, u32
parent_handle, const void *key,
return err;
}
+ if (response_length < TPM_RESPONSE_AUTH_LENGTH)
+ return TPM_LIB_ERROR;
+
err = verify_response_auth(0x00000041, response,
response_length - TPM_RESPONSE_AUTH_LENGTH,
4, &oiap_session,
@@ -817,6 +820,9 @@ u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32
key_handle,
oiap_session.valid = 0;
return err;
}
+ if (response_length < TPM_RESPONSE_AUTH_LENGTH)
+ return TPM_LIB_ERROR;
+
err = verify_response_auth(0x00000021, response,
response_length - TPM_RESPONSE_AUTH_LENGTH,
0, &oiap_session,
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index f443b738f82..aa4d3866d7b 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -519,6 +519,14 @@ u32 tpm2_get_capability(struct udevice *dev, u32
capability, u32 property,
*/
properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
sizeof(u8) + sizeof(u32);
+ if (response_len < properties_off)
+ return TPM_LIB_ERROR;
+
+ if (capability == TPM2_CAP_TPM_PROPERTIES &&
+ response_len - properties_off >
+ sizeof(u32) + prop_count * sizeof(struct tpms_tagged_property))
+ return TPM_LIB_ERROR;
+
memcpy(buf, &response[properties_off], response_len - properties_off);
return 0;
--
2.43.0