This pull request for TPM driver contains changes to unify TPM return
 code translation between trusted_tpm2 and TPM driver itself. Other than
 that the changes are either bug fixes or minor imrovements.
 
 Change log that should explain the previous iterations:
 
 1. "Documentation: tpm-security.rst: change title to section"
    https://lore.kernel.org/all/86514a6ab364e01f163470a91cacef120e1b8b47.camel@HansenPartnership.com/
 2. "drivers/char/tpm: use min() instead of min_t()"
    https://lore.kernel.org/all/20251201161228.3c09d88a@pumpkin/
 3. Removed spurious kfree(): https://lore.kernel.org/linux-integrity/aS+K5nO2MP7N+kxQ@ly-workstation/
 
 BR, Jarkko
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRE6pSOnaBC00OEHEIaerohdGur0gUCaTComgAKCRAaerohdGur
 0t38AQDThfcJhDmgfR3zYo0C8rtNQwM06fnooqsiDjTRHYXu6QEArRKJfR9B/vpN
 vIAloxIgIUxQbewBJ1DfxJ7OVO2kGwA=
 =hMwZ
 -----END PGP SIGNATURE-----

Merge tag 'tpmdd-next-6.19-rc1-v4' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull tpm updates from Jarkko Sakkinen:
 "This contains changes to unify TPM return code translation between
  trusted_tpm2 and TPM driver itself. Other than that the changes are
  either bug fixes or minor imrovements"

* tag 'tpmdd-next-6.19-rc1-v4' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  KEYS: trusted: Use tpm_ret_to_err() in trusted_tpm2
  tpm: Use -EPERM as fallback error code in tpm_ret_to_err
  tpm: Cap the number of PCR banks
  tpm: Remove tpm_find_get_ops
  tpm: add WQ_PERCPU to alloc_workqueue users
  tpm_crb: add missing loc parameter to kerneldoc
  tpm_crb: Fix a spelling mistake
  selftests: tpm2: Fix ill defined assertions
This commit is contained in:
Linus Torvalds 2025-12-04 19:30:09 -08:00
commit 028bd4a146
11 changed files with 42 additions and 81 deletions

View File

@ -230,42 +230,6 @@ struct tpm_chip *tpm_default_chip(void)
} }
EXPORT_SYMBOL_GPL(tpm_default_chip); 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 * tpm_dev_release() - free chip memory and the device number
* @dev: the character device for the TPM chip * @dev: the character device for the TPM chip
@ -282,7 +246,6 @@ static void tpm_dev_release(struct device *dev)
kfree(chip->work_space.context_buf); kfree(chip->work_space.context_buf);
kfree(chip->work_space.session_buf); kfree(chip->work_space.session_buf);
kfree(chip->allocated_banks);
#ifdef CONFIG_TCG_TPM2_HMAC #ifdef CONFIG_TCG_TPM2_HMAC
kfree(chip->auth); kfree(chip->auth);
#endif #endif

View File

@ -275,7 +275,8 @@ void tpm_common_release(struct file *file, struct file_priv *priv)
int __init tpm_dev_common_init(void) 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; return !tpm_dev_wq ? -ENOMEM : 0;
} }

View File

@ -313,10 +313,13 @@ int tpm_is_tpm2(struct tpm_chip *chip)
{ {
int rc; int rc;
chip = tpm_find_get_ops(chip);
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
tpm_put_ops(chip); tpm_put_ops(chip);
@ -338,10 +341,13 @@ int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
{ {
int rc; int rc;
chip = tpm_find_get_ops(chip);
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL); rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL);
else else
@ -369,10 +375,13 @@ int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
int rc; int rc;
int i; int i;
chip = tpm_find_get_ops(chip);
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
for (i = 0; i < chip->nr_allocated_banks; i++) { for (i = 0; i < chip->nr_allocated_banks; i++) {
if (digests[i].alg_id != chip->allocated_banks[i].alg_id) { if (digests[i].alg_id != chip->allocated_banks[i].alg_id) {
rc = -EINVAL; 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) if (!out || max > TPM_MAX_RNG_DATA)
return -EINVAL; return -EINVAL;
chip = tpm_find_get_ops(chip);
if (!chip) if (!chip)
return -ENODEV; return -ENODEV;
rc = tpm_try_get_ops(chip);
if (rc)
return rc;
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm2_get_random(chip, out, max); rc = tpm2_get_random(chip, out, max);
else else

View File

@ -267,7 +267,6 @@ static inline void tpm_msleep(unsigned int delay_msec)
int tpm_chip_bootstrap(struct tpm_chip *chip); int tpm_chip_bootstrap(struct tpm_chip *chip);
int tpm_chip_start(struct tpm_chip *chip); int tpm_chip_start(struct tpm_chip *chip);
void tpm_chip_stop(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, struct tpm_chip *tpm_chip_alloc(struct device *dev,
const struct tpm_class_ops *ops); const struct tpm_class_ops *ops);

View File

@ -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) 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].alg_id = TPM_ALG_SHA1;
chip->allocated_banks[0].digest_size = hash_digest_size[HASH_ALGO_SHA1]; chip->allocated_banks[0].digest_size = hash_digest_size[HASH_ALGO_SHA1];
chip->allocated_banks[0].crypto_id = HASH_ALGO_SHA1; chip->allocated_banks[0].crypto_id = HASH_ALGO_SHA1;

View File

@ -550,11 +550,9 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
nr_possible_banks = be32_to_cpup( nr_possible_banks = be32_to_cpup(
(__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
if (nr_possible_banks > TPM2_MAX_PCR_BANKS) {
chip->allocated_banks = kcalloc(nr_possible_banks, pr_err("tpm: out of bank capacity: %u > %u\n",
sizeof(*chip->allocated_banks), nr_possible_banks, TPM2_MAX_PCR_BANKS);
GFP_KERNEL);
if (!chip->allocated_banks) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }

View File

@ -179,6 +179,7 @@ static int crb_try_pluton_doorbell(struct crb_priv *priv, bool wait_for_complete
* *
* @dev: crb device * @dev: crb device
* @priv: crb private data * @priv: crb private data
* @loc: locality
* *
* Write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ * Write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ
* The device should respond within TIMEOUT_C by clearing the bit. * 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 * @dev: crb device
* @priv: crb private data * @priv: crb private data
* @loc: locality
* *
* Write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ * Write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ
* and poll till the device acknowledge it by clearing the bit. * and poll till the device acknowledge it by clearing the bit.
@ -412,7 +414,7 @@ static int crb_do_acpi_start(struct tpm_chip *chip)
#ifdef CONFIG_ARM64 #ifdef CONFIG_ARM64
/* /*
* This is a TPM Command Response Buffer start method that invokes a * 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. * a TPM 2.0 command.
*/ */
static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) static int tpm_crb_smc_start(struct device *dev, unsigned long func_id)

View File

@ -265,8 +265,7 @@ static u8 tpm_tis_status(struct tpm_chip *chip)
/* /*
* Dump stack for forensics, as invalid TPM_STS.x could be * Dump stack for forensics, as invalid TPM_STS.x could be
* potentially triggered by impaired tpm_try_get_ops() or * potentially triggered by impaired tpm_try_get_ops().
* tpm_find_get_ops().
*/ */
dump_stack(); dump_stack();
} }

View File

@ -26,7 +26,9 @@
#include <crypto/aes.h> #include <crypto/aes.h>
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */ #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 tpm_chip;
struct trusted_key_payload; struct trusted_key_payload;
@ -68,7 +70,7 @@ enum tpm2_curves {
struct tpm_digest { struct tpm_digest {
u16 alg_id; u16 alg_id;
u8 digest[TPM_MAX_DIGEST_SIZE]; u8 digest[TPM2_MAX_DIGEST_SIZE];
} __packed; } __packed;
struct tpm_bank_info { struct tpm_bank_info {
@ -189,7 +191,7 @@ struct tpm_chip {
unsigned int groups_cnt; unsigned int groups_cnt;
u32 nr_allocated_banks; u32 nr_allocated_banks;
struct tpm_bank_info *allocated_banks; struct tpm_bank_info allocated_banks[TPM2_MAX_PCR_BANKS];
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
acpi_handle acpi_dev_handle; acpi_handle acpi_dev_handle;
char ppi_version[TPM_PPI_VERSION_LEN + 1]; char ppi_version[TPM_PPI_VERSION_LEN + 1];
@ -454,8 +456,10 @@ static inline ssize_t tpm_ret_to_err(ssize_t ret)
return 0; return 0;
case TPM2_RC_SESSION_MEMORY: case TPM2_RC_SESSION_MEMORY:
return -ENOMEM; return -ENOMEM;
case TPM2_RC_HASH:
return -EINVAL;
default: default:
return -EFAULT; return -EPERM;
} }
} }

View File

@ -333,25 +333,19 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
} }
blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len); blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);
if (blob_len < 0)
rc = blob_len;
out: out:
tpm_buf_destroy(&sized); tpm_buf_destroy(&sized);
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
if (rc > 0) { if (!rc)
if (tpm2_rc_value(rc) == TPM2_RC_HASH)
rc = -EINVAL;
else
rc = -EPERM;
}
if (blob_len < 0)
rc = blob_len;
else
payload->blob_len = blob_len; payload->blob_len = blob_len;
out_put: out_put:
tpm_put_ops(chip); 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: out:
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
if (rc > 0) return tpm_ret_to_err(rc);
rc = -EPERM;
return rc;
} }
/** /**
@ -521,8 +512,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
tpm_buf_fill_hmac_session(chip, &buf); tpm_buf_fill_hmac_session(chip, &buf);
rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
rc = tpm_buf_check_hmac_response(chip, &buf, rc); rc = tpm_buf_check_hmac_response(chip, &buf, rc);
if (rc > 0)
rc = -EPERM;
if (!rc) { if (!rc) {
data_len = be16_to_cpup( data_len = be16_to_cpup(
@ -555,7 +544,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
out: out:
tpm_buf_destroy(&buf); 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: out:
tpm_put_ops(chip); tpm_put_ops(chip);
return tpm_ret_to_err(rc);
return rc;
} }

View File

@ -437,7 +437,7 @@ class Client:
def extend_pcr(self, i, dig, bank_alg = TPM2_ALG_SHA1): def extend_pcr(self, i, dig, bank_alg = TPM2_ALG_SHA1):
ds = get_digest_size(bank_alg) ds = get_digest_size(bank_alg)
assert(ds == len(dig)) assert ds == len(dig)
auth_cmd = AuthCommand() auth_cmd = AuthCommand()
@ -589,7 +589,7 @@ class Client:
def seal(self, parent_key, data, auth_value, policy_dig, def seal(self, parent_key, data, auth_value, policy_dig,
name_alg = TPM2_ALG_SHA1): name_alg = TPM2_ALG_SHA1):
ds = get_digest_size(name_alg) 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 attributes = 0
if not policy_dig: if not policy_dig: