From 071aa806f00cf2948ce8082102d5f64515f53215 Mon Sep 17 00:00:00 2001 From: Yuqi Xu Date: Mon, 28 Sep 2026 16:27:00 +0800 Subject: [PATCH] tpm: reject duplicate PCR banks in tpm2_get_pcr_allocation The TPM2_CAP_PCRS response is external input. tpm2_get_pcr_allocation() adds every active selection to allocated_banks, while tpm_sysfs_add_device() has one group slot per distinct hash algorithm. Eight duplicate selections can therefore write past chip->groups[]. The TPM protocol does not allow a hash algorithm to appear twice in this capability response. Treat a duplicate as a broken TPM and return -EIO so the chip is not enabled, instead of silently dropping the extra selection. Assisted-by: LLM Signed-off-by: Yuqi Xu Reviewed-by: Ren Wei Reviewed-by: Jarkko Sakkinen Link: https://lore.kernel.org/r/9d27c4513a3c6fc32f9574ba192cd3bfcb2bac98.1790568982.git.xuyuqiabc@gmail.com Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm2-cmd.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 119c73a603e6..4b2bb2ddc321 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -528,6 +528,7 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) u32 rsp_len; int rc; int i = 0; + int j; struct tpm_buf *buf __free(kfree) = kzalloc(TPM_BUFSIZE, GFP_KERNEL); if (!buf) @@ -570,6 +571,23 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0, pcr_selection.size_of_select); if (pcr_select_offset) { + for (j = 0; j < nr_alloc_banks; j++) { + if (chip->allocated_banks[j].alg_id == hash_alg) + break; + } + + /* + * The TPM protocol does not allow the same hash + * algorithm twice. A duplicate means this device + * is not behaving; do not enable it. + */ + if (j != nr_alloc_banks) { + pr_err("tpm: duplicate PCR bank for algorithm 0x%04x\n", + hash_alg); + rc = -EIO; + break; + } + chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg; rc = tpm2_init_bank_info(chip, nr_alloc_banks);