From: Eric Biggers <ebiggers@xxxxxxxxxx> extract_key_parameters() can read past the end of the input buffer due to buggy and missing bounds checks. Fix it as follows: - Before reading each key length field, verify that there are at least 4 bytes remaining. - Avoid integer overflows when validating size fields; 'sz + 12' and '4 + sz' overflowed if 'sz' is near U32_MAX. - Before saving the pointer to the public key, check that it doesn't run past the end of the buffer. Fixes: f8c54e1ac4b8 ("KEYS: asym_tpm: extract key size & public key [ver #2]") Cc: <stable@xxxxxxxxxxxxxxx> # v4.20+ Signed-off-by: Eric Biggers <ebiggers@xxxxxxxxxx> --- crypto/asymmetric_keys/asym_tpm.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c index 0959613560b9..60d20d44c885 100644 --- a/crypto/asymmetric_keys/asym_tpm.c +++ b/crypto/asymmetric_keys/asym_tpm.c @@ -814,7 +814,6 @@ static int extract_key_parameters(struct tpm_key *tk) { const void *cur = tk->blob; uint32_t len = tk->blob_len; - const void *pub_key; uint32_t sz; uint32_t key_len; @@ -845,14 +844,14 @@ static int extract_key_parameters(struct tpm_key *tk) return -EBADMSG; sz = get_unaligned_be32(cur + 8); - if (len < sz + 12) - return -EBADMSG; /* Move to TPM_RSA_KEY_PARMS */ - len -= 12; cur += 12; + len -= 12; /* Grab the RSA key length */ + if (len < 4) + return -EBADMSG; key_len = get_unaligned_be32(cur); switch (key_len) { @@ -866,29 +865,36 @@ static int extract_key_parameters(struct tpm_key *tk) } /* Move just past TPM_KEY_PARMS */ + if (len < sz) + return -EBADMSG; cur += sz; len -= sz; if (len < 4) return -EBADMSG; - sz = get_unaligned_be32(cur); - if (len < 4 + sz) - return -EBADMSG; + cur += 4; + len -= 4; /* Move to TPM_STORE_PUBKEY */ - cur += 4 + sz; - len -= 4 + sz; + if (len < sz) + return -EBADMSG; + cur += sz; + len -= sz; /* Grab the size of the public key, it should jive with the key size */ + if (len < 4) + return -EBADMSG; sz = get_unaligned_be32(cur); + cur += 4; + len -= 4; if (sz > 256) return -EINVAL; - - pub_key = cur + 4; + if (len < sz) + return -EBADMSG; tk->key_len = key_len; - tk->pub_key = pub_key; + tk->pub_key = cur; tk->pub_key_len = sz; return 0; -- 2.34.1