tpm2-sessions: Fix tpm2_read_public range checks
Subsystems (3)
Jarkko Sakkinen
maintainerPATCH 1/1 tpm2-sessions: Fix tpm2_read_public range checks
'tpm2_read_public' has some rudimentary range checks but does not explicitly check that both fields of TPMT_HA actually fit within the buffer size limits.
Introduce a new function 'tpm2_resolve_name' to address all the possible out-of-range issues, and in addition do handle type validation.
Cc [email protected] # v6.10+
Fixes d0a25bb961e6 ("tpm: Add HMAC session name/handle append")
Signed-off-by Jarkko Sakkinen <[email protected]>
--- drivers/char/tpm/tpm2-cmd.c | 95 ++++++++++++++++++++++++++++++++ drivers/char/tpm/tpm2-sessions.c | 78 +------------------------- include/linux/tpm.h | 2 + 3 files changed, 98 insertions(+), 77 deletions(-)
drivers/char/tpm/tpm2-cmd.c +95 -0
@@ -11,8 +11,11 @@* used by the kernel internally. */ +#include "linux/dev_printk.h" +#include "linux/tpm.h" #include "tpm.h" #include <crypto/hash_info.h> +#include <linux/unaligned.h> static bool disable_pcr_integrity;module_param (disable_pcr_integrity, bool,0444 );
@@ -769,3 +772,95 @@ int tpm2_find_cc(struct tpm_chip *chip, u32 cc)return -1 ; } + +/** +* tpm2_name_size() - Resolve size of a TPMT_HA instance +* @name: Pointer to TPMT_HA structure extracted from TPM2B_NAME. +* +* Calculate size of the TPMT_HA payload of TPM2B_NAME. It is used with +* transient keys, persistent and NV indexes. +* +* Returns zero when the hash size was successfully calculated. +* Returns -EINVAL when the hash algorithm was not recognized. +*/ +int tpm2_name_size (const u8 *name) +{ +u16 hash_alg =get_unaligned_be16 (name); + +switch (hash_alg) { +case TPM_ALG_SHA1 : +return SHA1_DIGEST_SIZE +2 ; +case TPM_ALG_SHA256 : +return SHA256_DIGEST_SIZE +2 ; +case TPM_ALG_SHA384 : +return SHA384_DIGEST_SIZE +2 ; +case TPM_ALG_SHA512 : +return SHA512_DIGEST_SIZE +2 ; +case TPM_ALG_SM3_256 : +return SM3256_DIGEST_SIZE +2 ; + } + +return -EINVAL ; +} + +/** +* tpm2_resolve_name - Resolve TPM object's name from the public area +* @handle: Persistent, transient or nv handle. +* +* Returns zero on success. +* Returns -EINVAL when handles are not of valid type. +* Returns -EIO if the transmission fails or response is malformed. +*/ +int tpm2_resolve_name (struct tpm_chip *chip,u32 handle,void *name) +{ +u32 mso =tpm2_handle_mso (handle); +off_t offset =TPM_HEADER_SIZE ; +int name_size, name_size_2; +struct tpm_buf buf; +int rc; + +if (mso !=TPM2_MSO_PERSISTENT && mso !=TPM2_MSO_VOLATILE && + mso !=TPM2_MSO_NVRAM ) +return -EINVAL ; + + rc =tpm_buf_init (&buf,TPM2_ST_NO_SESSIONS ,TPM2_CC_READ_PUBLIC ); +if (rc) +return rc; + +tpm_buf_append_u32 (&buf, handle); + + rc =tpm_transmit_cmd (chip, &buf,0 ,"TPM2_ReadPublic" ); +if (rc) { +tpm_buf_destroy (&buf); +return tpm_ret_to_err (rc); + } + +/* Skip TPMT_PUBLIC: */ + offset +=tpm_buf_read_u16 (&buf, &offset); + +/* +* Ensure space for the length field of TPM2B_NAME and hashAlg field of +* TPMT_HA (the extra four bytes). +*/ +if (offset +4 >tpm_buf_length (&buf)) { +tpm_buf_destroy (&buf); +return -EIO ; + } + + name_size =tpm_buf_read_u16 (&buf, &offset); + name_size_2 =tpm2_name_size (&buf.data[offset]); + +if (name_size != name_size_2) { +tpm_buf_destroy (&buf); +return -EIO ; + } + +if (offset + name_size >tpm_buf_length (&buf)) { +tpm_buf_destroy (&buf); +return -EIO ; + } + +memcpy (name, &buf.data[offset], name_size); +return 0 ; +} +EXPORT_SYMBOL_GPL (tpm2_resolve_name);
drivers/char/tpm/tpm2-sessions.c +1 -77
90 lines not on this page · raw message
include/linux/tpm.h +2 -0
@@ -477,6 +477,8 @@ extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,extern int tpm_get_random (struct tpm_chip *chip,u8 *data,size_t max);extern struct tpm_chip *tpm_default_chip (void );void tpm2_flush_context (struct tpm_chip *chip,u32 handle); +int tpm2_name_size (const u8 *name); +int tpm2_resolve_name (struct tpm_chip *chip,u32 handle,void *name);static inline void tpm_buf_append_empty_auth (struct tpm_buf *buf,u32 handle) {
Signature · 1 line
2.52.0