On Thu, Dec 04, 2025 at 12:12:12AM +0200, Jarkko Sakkinen wrote:
'tpm2_read_public' has some rudimentary range checks but the function does not ensure that the response buffer has enough bytes for the full TPMT_HA payload.
Re-implement the function with necessary checks and validation.
Cc: stable@vger.kernel.org # v6.10+ Fixes: d0a25bb961e6 ("tpm: Add HMAC session name/handle append") Signed-off-by: Jarkko Sakkinen jarkko@kernel.org
A minor nit about variable naming, but:
Reviewed-by: Jonathan McDowell noodles@meta.com
v2:
- Made the fix localized instead of spread all over the place.
drivers/char/tpm/tpm2-cmd.c | 3 ++ drivers/char/tpm/tpm2-sessions.c | 77 +++++++++++++++++--------------- 2 files changed, 44 insertions(+), 36 deletions(-)
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index be4a9c7f2e1a..34e3599f094f 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -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); diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c index a265e9752a5e..e9f439be3916 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -163,54 +163,59 @@ static int name_size(const u8 *name) } }
-static int tpm2_parse_read_public(char *name, struct tpm_buf *buf) +static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name) {
- struct tpm_header *head = (struct tpm_header *)buf->data;
- u32 mso = tpm2_handle_mso(handle); off_t offset = TPM_HEADER_SIZE;
- u32 tot_len = be32_to_cpu(head->length);
- int ret;
- u32 val;
- /* we're starting after the header so adjust the length */
- tot_len -= TPM_HEADER_SIZE;
- /* skip public */
- val = tpm_buf_read_u16(buf, &offset);
- if (val > tot_len)
return -EINVAL;- offset += val;
- /* name */
- val = tpm_buf_read_u16(buf, &offset);
- ret = name_size(&buf->data[offset]);
- if (ret < 0)
return ret;
- struct tpm_buf buf;
- int rc, rc2;
- if (val != ret)
- if (mso != TPM2_MSO_PERSISTENT && mso != TPM2_MSO_VOLATILE &&
return -EINVAL;mso != TPM2_MSO_NVRAM)
- memcpy(name, &buf->data[offset], val);
- /* forget the rest */
- return 0;
-}
-static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name) -{
struct tpm_buf buf;
int rc;
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, "read public");
if (rc == TPM2_RC_SUCCESS)
rc = tpm2_parse_read_public(name, &buf);tpm_buf_destroy(&buf);
- rc = tpm_transmit_cmd(chip, &buf, 0, "TPM2_ReadPublic");
- if (rc) {
tpm_buf_destroy(&buf);return tpm_ret_to_err(rc);- }
- return 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;- }
- rc = tpm_buf_read_u16(&buf, &offset);
- rc2 = name_size(&buf.data[offset]);
rc2 is not great naming. We only use it for this, so perhaps name_len?
- if (rc2 < 0)
return rc2;- if (rc != rc2) {
tpm_buf_destroy(&buf);return -EIO;- }
- if (offset + rc > tpm_buf_length(&buf)) {
tpm_buf_destroy(&buf);return -EIO;- }
- memcpy(name, &buf.data[offset], rc);
- return 0;
} #endif /* CONFIG_TCG_TPM2_HMAC */
-- 2.52.0
J.