From cffc934c0d81c9dea3d63cc108e6f925a4bac18e Mon Sep 17 00:00:00 2001 From: Maurice Hieronymus Date: Sun, 23 Nov 2025 12:18:09 +0100 Subject: [PATCH 1/8] selftests: tpm2: Fix ill defined assertions Remove parentheses around assert statements in Python. With parentheses, assert always evaluates to True, making the checks ineffective. Signed-off-by: Maurice Hieronymus Signed-off-by: Jarkko Sakkinen --- tools/testing/selftests/tpm2/tpm2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/tpm2/tpm2.py b/tools/testing/selftests/tpm2/tpm2.py index bba8cb54548e..3d130c30bc7c 100644 --- a/tools/testing/selftests/tpm2/tpm2.py +++ b/tools/testing/selftests/tpm2/tpm2.py @@ -437,7 +437,7 @@ class Client: def extend_pcr(self, i, dig, bank_alg = TPM2_ALG_SHA1): ds = get_digest_size(bank_alg) - assert(ds == len(dig)) + assert ds == len(dig) auth_cmd = AuthCommand() @@ -589,7 +589,7 @@ class Client: def seal(self, parent_key, data, auth_value, policy_dig, name_alg = TPM2_ALG_SHA1): ds = get_digest_size(name_alg) - assert(not policy_dig or ds == len(policy_dig)) + assert not policy_dig or ds == len(policy_dig) attributes = 0 if not policy_dig: From 76b1a8aebe0d326fe85f7af139ab86a5c628a016 Mon Sep 17 00:00:00 2001 From: Chu Guangqing Date: Tue, 25 Nov 2025 10:30:30 +0800 Subject: [PATCH 2/8] tpm_crb: Fix a spelling mistake The spelling of the word "requrest" is incorrect; it should be "request". Signed-off-by: Chu Guangqing Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index c75a531cfb98..e094c517b96e 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -412,7 +412,7 @@ static int crb_do_acpi_start(struct tpm_chip *chip) #ifdef CONFIG_ARM64 /* * This is a TPM Command Response Buffer start method that invokes a - * Secure Monitor Call to requrest the firmware to execute or cancel + * Secure Monitor Call to request the firmware to execute or cancel * a TPM 2.0 command. */ static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) From 61872214870e0cb0dc2e6d823f2362f11e87f4eb Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Mon, 27 Oct 2025 21:09:21 -0500 Subject: [PATCH 3/8] tpm_crb: add missing loc parameter to kerneldoc Update the kerneldoc parameter definitions for __crb_go_idle and __crb_cmd_ready to include the loc parameter. Signed-off-by: Stuart Yoder Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index e094c517b96e..6c25305c256e 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -179,6 +179,7 @@ static int crb_try_pluton_doorbell(struct crb_priv *priv, bool wait_for_complete * * @dev: crb device * @priv: crb private data + * @loc: locality * * Write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ * The device should respond within TIMEOUT_C by clearing the bit. @@ -233,6 +234,7 @@ static int crb_go_idle(struct tpm_chip *chip) * * @dev: crb device * @priv: crb private data + * @loc: locality * * Write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ * and poll till the device acknowledge it by clearing the bit. From e68407b6b0c7c5a4b873bbbd0758a2aed857dc3f Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Thu, 6 Nov 2025 17:28:00 +0100 Subject: [PATCH 4/8] tpm: add WQ_PERCPU to alloc_workqueue users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently if a user enqueues a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistency cannot be addressed without refactoring the API. alloc_workqueue() treats all queues as per-CPU by default, while unbound workqueues must opt-in via WQ_UNBOUND. This default is suboptimal: most workloads benefit from unbound queues, allowing the scheduler to place worker threads where they’re needed and reducing noise when CPUs are isolated. This continues the effort to refactor workqueue APIs, which began with the introduction of new workqueues and a new alloc_workqueue flag in: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") This change adds a new WQ_PERCPU flag to explicitly request alloc_workqueue() to be per-cpu when WQ_UNBOUND has not been specified. With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND), any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND must now use WQ_PERCPU. Once migration is complete, WQ_UNBOUND can be removed and unbound will become the implicit default. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-dev-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index f2a5e09257dd..f942c0c8e402 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -275,7 +275,8 @@ void tpm_common_release(struct file *file, struct file_priv *priv) int __init tpm_dev_common_init(void) { - tpm_dev_wq = alloc_workqueue("tpm_dev_wq", WQ_MEM_RECLAIM, 0); + tpm_dev_wq = alloc_workqueue("tpm_dev_wq", WQ_MEM_RECLAIM | WQ_PERCPU, + 0); return !tpm_dev_wq ? -ENOMEM : 0; } From 020a0d8feac0fd8a6f6c545c55f5990875226a0b Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Thu, 27 Nov 2025 17:02:29 +0000 Subject: [PATCH 5/8] tpm: Remove tpm_find_get_ops tpm_find_get_ops() looks for the first valid TPM if the caller passes in NULL. All internal users have been converted to either associate themselves with a TPM directly, or call tpm_default_chip() as part of their setup. Remove the no longer necessary tpm_find_get_ops(). Reviewed-by: Jarkko Sakkinen Signed-off-by: Jonathan McDowell Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 36 -------------------------------- drivers/char/tpm/tpm-interface.c | 20 ++++++++++++++---- drivers/char/tpm/tpm.h | 1 - drivers/char/tpm/tpm_tis_core.c | 3 +-- 4 files changed, 17 insertions(+), 43 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e25daf2396d3..30d00219f9f3 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -230,42 +230,6 @@ struct tpm_chip *tpm_default_chip(void) } EXPORT_SYMBOL_GPL(tpm_default_chip); -/** - * tpm_find_get_ops() - find and reserve a TPM chip - * @chip: a &struct tpm_chip instance, %NULL for the default chip - * - * Finds a TPM chip and reserves its class device and operations. The chip must - * be released with tpm_put_ops() after use. - * This function is for internal use only. It supports existing TPM callers - * by accepting NULL, but those callers should be converted to pass in a chip - * directly. - * - * Return: - * A reserved &struct tpm_chip instance. - * %NULL if a chip is not found. - * %NULL if the chip is not available. - */ -struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip) -{ - int rc; - - if (chip) { - if (!tpm_try_get_ops(chip)) - return chip; - return NULL; - } - - chip = tpm_default_chip(); - if (!chip) - return NULL; - rc = tpm_try_get_ops(chip); - /* release additional reference we got from tpm_default_chip() */ - put_device(&chip->dev); - if (rc) - return NULL; - return chip; -} - /** * tpm_dev_release() - free chip memory and the device number * @dev: the character device for the TPM chip diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index c9f173001d0e..f745a098908b 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -313,10 +313,13 @@ int tpm_is_tpm2(struct tpm_chip *chip) { int rc; - chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; + rc = tpm_try_get_ops(chip); + if (rc) + return rc; + rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; tpm_put_ops(chip); @@ -338,10 +341,13 @@ int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, { int rc; - chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; + rc = tpm_try_get_ops(chip); + if (rc) + return rc; + if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL); else @@ -369,10 +375,13 @@ int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, int rc; int i; - chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; + rc = tpm_try_get_ops(chip); + if (rc) + return rc; + for (i = 0; i < chip->nr_allocated_banks; i++) { if (digests[i].alg_id != chip->allocated_banks[i].alg_id) { rc = -EINVAL; @@ -492,10 +501,13 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) if (!out || max > TPM_MAX_RNG_DATA) return -EINVAL; - chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; + rc = tpm_try_get_ops(chip); + if (rc) + return rc; + if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_get_random(chip, out, max); else diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2726bd38e5ac..02c07fef41ba 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -267,7 +267,6 @@ static inline void tpm_msleep(unsigned int delay_msec) int tpm_chip_bootstrap(struct tpm_chip *chip); int tpm_chip_start(struct tpm_chip *chip); void tpm_chip_stop(struct tpm_chip *chip); -struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip); struct tpm_chip *tpm_chip_alloc(struct device *dev, const struct tpm_class_ops *ops); diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 8954a8660ffc..e2a1769081b1 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -265,8 +265,7 @@ static u8 tpm_tis_status(struct tpm_chip *chip) /* * Dump stack for forensics, as invalid TPM_STS.x could be - * potentially triggered by impaired tpm_try_get_ops() or - * tpm_find_get_ops(). + * potentially triggered by impaired tpm_try_get_ops(). */ dump_stack(); } From faf07e611dfa464b201223a7253e9dc5ee0f3c9e Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 30 Sep 2025 15:58:02 +0300 Subject: [PATCH 6/8] tpm: Cap the number of PCR banks tpm2_get_pcr_allocation() does not cap any upper limit for the number of banks. Cap the limit to eight banks so that out of bounds values coming from external I/O cause on only limited harm. Cc: stable@vger.kernel.org # v5.10+ Fixes: bcfff8384f6c ("tpm: dynamically allocate the allocated_banks array") Tested-by: Lai Yi Reviewed-by: Jonathan McDowell Reviewed-by: Roberto Sassu Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 1 - drivers/char/tpm/tpm1-cmd.c | 5 ----- drivers/char/tpm/tpm2-cmd.c | 8 +++----- include/linux/tpm.h | 8 +++++--- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 30d00219f9f3..082b910ddf0d 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -246,7 +246,6 @@ static void tpm_dev_release(struct device *dev) kfree(chip->work_space.context_buf); kfree(chip->work_space.session_buf); - kfree(chip->allocated_banks); #ifdef CONFIG_TCG_TPM2_HMAC kfree(chip->auth); #endif diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c index cf64c7385105..b49a790f1bd5 100644 --- a/drivers/char/tpm/tpm1-cmd.c +++ b/drivers/char/tpm/tpm1-cmd.c @@ -799,11 +799,6 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr) */ int tpm1_get_pcr_allocation(struct tpm_chip *chip) { - chip->allocated_banks = kcalloc(1, sizeof(*chip->allocated_banks), - GFP_KERNEL); - if (!chip->allocated_banks) - return -ENOMEM; - chip->allocated_banks[0].alg_id = TPM_ALG_SHA1; chip->allocated_banks[0].digest_size = hash_digest_size[HASH_ALGO_SHA1]; chip->allocated_banks[0].crypto_id = HASH_ALGO_SHA1; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 5532e53a2dd3..dd502322f499 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -550,11 +550,9 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) nr_possible_banks = be32_to_cpup( (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); - - chip->allocated_banks = kcalloc(nr_possible_banks, - sizeof(*chip->allocated_banks), - GFP_KERNEL); - if (!chip->allocated_banks) { + if (nr_possible_banks > TPM2_MAX_PCR_BANKS) { + pr_err("tpm: out of bank capacity: %u > %u\n", + nr_possible_banks, TPM2_MAX_PCR_BANKS); rc = -ENOMEM; goto out; } diff --git a/include/linux/tpm.h b/include/linux/tpm.h index b15360ff78d7..53de9488c509 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -26,7 +26,9 @@ #include #define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */ -#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE + +#define TPM2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE +#define TPM2_MAX_PCR_BANKS 8 struct tpm_chip; struct trusted_key_payload; @@ -68,7 +70,7 @@ enum tpm2_curves { struct tpm_digest { u16 alg_id; - u8 digest[TPM_MAX_DIGEST_SIZE]; + u8 digest[TPM2_MAX_DIGEST_SIZE]; } __packed; struct tpm_bank_info { @@ -189,7 +191,7 @@ struct tpm_chip { unsigned int groups_cnt; u32 nr_allocated_banks; - struct tpm_bank_info *allocated_banks; + struct tpm_bank_info allocated_banks[TPM2_MAX_PCR_BANKS]; #ifdef CONFIG_ACPI acpi_handle acpi_dev_handle; char ppi_version[TPM_PPI_VERSION_LEN + 1]; From 7fcf459ac84c42a4ef63a650dccc345602cf4da6 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 30 Sep 2025 16:02:54 +0300 Subject: [PATCH 7/8] tpm: Use -EPERM as fallback error code in tpm_ret_to_err Using -EFAULT as the tpm_ret_to_err() fallback error code causes makes it incompatible on how trusted keys transmute TPM return codes. Change the fallback as -EPERM in order to gain compatibility with trusted keys. In addition, map TPM_RC_HASH to -EINVAL in order to be compatible with tpm2_seal_trusted() return values. Signed-off-by: Jarkko Sakkinen Reviewed-by: Stefano Garzarella Signed-off-by: Jarkko Sakkinen --- include/linux/tpm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 53de9488c509..3d8f7d1ce2b8 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -456,8 +456,10 @@ static inline ssize_t tpm_ret_to_err(ssize_t ret) return 0; case TPM2_RC_SESSION_MEMORY: return -ENOMEM; + case TPM2_RC_HASH: + return -EINVAL; default: - return -EFAULT; + return -EPERM; } } From 09b71a58ee355ae09f302bd0875a29ffbcbbe3ac Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 30 Sep 2025 16:06:51 +0300 Subject: [PATCH 8/8] KEYS: trusted: Use tpm_ret_to_err() in trusted_tpm2 Use tpm_ret_to_err() to transmute TPM return codes in trusted_tpm2. Signed-off-by: Jarkko Sakkinen Acked-by: Stefano Garzarella Signed-off-by: Jarkko Sakkinen --- security/keys/trusted-keys/trusted_tpm2.c | 26 ++++++----------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c index 91656e44b326..8bc6efa8accb 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -333,25 +333,19 @@ int tpm2_seal_trusted(struct tpm_chip *chip, } blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len); + if (blob_len < 0) + rc = blob_len; out: tpm_buf_destroy(&sized); tpm_buf_destroy(&buf); - if (rc > 0) { - if (tpm2_rc_value(rc) == TPM2_RC_HASH) - rc = -EINVAL; - else - rc = -EPERM; - } - if (blob_len < 0) - rc = blob_len; - else + if (!rc) payload->blob_len = blob_len; out_put: tpm_put_ops(chip); - return rc; + return tpm_ret_to_err(rc); } /** @@ -455,10 +449,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip, out: tpm_buf_destroy(&buf); - if (rc > 0) - rc = -EPERM; - - return rc; + return tpm_ret_to_err(rc); } /** @@ -521,8 +512,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, tpm_buf_fill_hmac_session(chip, &buf); rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); rc = tpm_buf_check_hmac_response(chip, &buf, rc); - if (rc > 0) - rc = -EPERM; if (!rc) { data_len = be16_to_cpup( @@ -555,7 +544,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, out: tpm_buf_destroy(&buf); - return rc; + return tpm_ret_to_err(rc); } /** @@ -587,6 +576,5 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, out: tpm_put_ops(chip); - - return rc; + return tpm_ret_to_err(rc); }