Skip to content

Commit

Permalink
Merge tag 'tpmdd-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/jarkko/linux-tpmdd

Pull tpm updates from Jarkko Sakkinen:

 - The .machine keyring, used for Machine Owner Keys (MOK), acquired the
   ability to store only CA enforced keys, and put rest to the .platform
   keyring, thus separating the code signing keys from the keys that are
   used to sign certificates.

   This essentially unlocks the use of the .machine keyring as a trust
   anchor for IMA. It is an opt-in feature, meaning that the additional
   contraints won't brick anyone who does not care about them.

 - Enable interrupt based transactions with discrete TPM chips (tpm_tis).

   There was code for this existing but it never really worked so I
   consider this a new feature rather than a bug fix. Before the driver
   just fell back to the polling mode.

Link: https://lore.kernel.org/linux-integrity/a93b6222-edda-d43c-f010-a59701f2aeef@gmx.de/
Link: https://lore.kernel.org/linux-integrity/20230302164652.83571-1-eric.snowberg@oracle.com/

* tag 'tpmdd-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd: (29 commits)
  tpm: Add !tpm_amd_is_rng_defective() to the hwrng_unregister() call site
  tpm_tis: fix stall after iowrite*()s
  tpm/tpm_tis_synquacer: Convert to platform remove callback returning void
  tpm/tpm_tis: Convert to platform remove callback returning void
  tpm/tpm_ftpm_tee: Convert to platform remove callback returning void
  tpm: tpm_tis_spi: Mark ACPI and OF related data as maybe unused
  tpm: st33zp24: Mark ACPI and OF related data as maybe unused
  tpm, tpm_tis: Enable interrupt test
  tpm, tpm_tis: startup chip before testing for interrupts
  tpm, tpm_tis: Claim locality when interrupts are reenabled on resume
  tpm, tpm_tis: Claim locality in interrupt handler
  tpm, tpm_tis: Request threaded interrupt handler
  tpm, tpm: Implement usage counter for locality
  tpm, tpm_tis: do not check for the active locality in interrupt handler
  tpm, tpm_tis: Move interrupt mask checks into own function
  tpm, tpm_tis: Only handle supported interrupts
  tpm, tpm_tis: Claim locality before writing interrupt registers
  tpm, tpm_tis: Do not skip reset of original interrupt vector
  tpm, tpm_tis: Disable interrupts if tpm_tis_probe_irq() failed
  tpm, tpm_tis: Claim locality before writing TPM_INT_ENABLE register
  ...
  • Loading branch information
Linus Torvalds committed Apr 24, 2023
2 parents dc7e22a + bd8621c commit 1a0beef
Show file tree
Hide file tree
Showing 18 changed files with 431 additions and 162 deletions.
14 changes: 11 additions & 3 deletions certs/system_keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ extern __initconst const unsigned long system_certificate_list_size;
extern __initconst const unsigned long module_cert_size;

/**
* restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA
* restrict_link_by_builtin_trusted - Restrict keyring addition by built-in CA
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @restriction_key: A ring of keys that can be used to vouch for the new cert.
*
* Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in the built in system keyring.
Expand All @@ -50,7 +54,11 @@ int restrict_link_by_builtin_trusted(struct key *dest_keyring,
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
/**
* restrict_link_by_builtin_and_secondary_trusted - Restrict keyring
* addition by both builtin and secondary keyrings
* addition by both built-in and secondary keyrings.
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @restrict_key: A ring of keys that can be used to vouch for the new cert.
*
* Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in either the built-in or the secondary system
Expand All @@ -75,7 +83,7 @@ int restrict_link_by_builtin_and_secondary_trusted(
secondary_trusted_keys);
}

/**
/*
* Allocate a struct key_restriction for the "builtin and secondary trust"
* keyring. Only for use in system_trusted_keyring_init().
*/
Expand Down
40 changes: 40 additions & 0 deletions crypto/asymmetric_keys/restrict.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,46 @@ int restrict_link_by_signature(struct key *dest_keyring,
return ret;
}

/**
* restrict_link_by_ca - Restrict additions to a ring of CA keys
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @trust_keyring: Unused.
*
* Check if the new certificate is a CA. If it is a CA, then mark the new
* certificate as being ok to link.
*
* Returns 0 if the new certificate was accepted, -ENOKEY if the
* certificate is not a CA. -ENOPKG if the signature uses unsupported
* crypto, or some other error if there is a matching certificate but
* the signature check cannot be performed.
*/
int restrict_link_by_ca(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring)
{
const struct public_key *pkey;

if (type != &key_type_asymmetric)
return -EOPNOTSUPP;

pkey = payload->data[asym_crypto];
if (!pkey)
return -ENOPKG;
if (!test_bit(KEY_EFLAG_CA, &pkey->key_eflags))
return -ENOKEY;
if (!test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags))
return -ENOKEY;
if (!IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING_MAX))
return 0;
if (test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags))
return -ENOKEY;

return 0;
}

static bool match_either_id(const struct asymmetric_key_id **pair,
const struct asymmetric_key_id *single)
{
Expand Down
50 changes: 50 additions & 0 deletions crypto/asymmetric_keys/x509_cert_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,13 +579,63 @@ int x509_process_extension(void *context, size_t hdrlen,
return 0;
}

if (ctx->last_oid == OID_keyUsage) {
/*
* Get hold of the keyUsage bit string
* v[1] is the encoding size
* (Expect either 0x02 or 0x03, making it 1 or 2 bytes)
* v[2] is the number of unused bits in the bit string
* (If >= 3 keyCertSign is missing when v[1] = 0x02)
* v[3] and possibly v[4] contain the bit string
*
* From RFC 5280 4.2.1.3:
* 0x04 is where keyCertSign lands in this bit string
* 0x80 is where digitalSignature lands in this bit string
*/
if (v[0] != ASN1_BTS)
return -EBADMSG;
if (vlen < 4)
return -EBADMSG;
if (v[2] >= 8)
return -EBADMSG;
if (v[3] & 0x80)
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_DIGITALSIG;
if (v[1] == 0x02 && v[2] <= 2 && (v[3] & 0x04))
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN;
else if (vlen > 4 && v[1] == 0x03 && (v[3] & 0x04))
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN;
return 0;
}

if (ctx->last_oid == OID_authorityKeyIdentifier) {
/* Get hold of the CA key fingerprint */
ctx->raw_akid = v;
ctx->raw_akid_size = vlen;
return 0;
}

if (ctx->last_oid == OID_basicConstraints) {
/*
* Get hold of the basicConstraints
* v[1] is the encoding size
* (Expect 0x2 or greater, making it 1 or more bytes)
* v[2] is the encoding type
* (Expect an ASN1_BOOL for the CA)
* v[3] is the contents of the ASN1_BOOL
* (Expect 1 if the CA is TRUE)
* vlen should match the entire extension size
*/
if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ))
return -EBADMSG;
if (vlen < 2)
return -EBADMSG;
if (v[1] != vlen - 2)
return -EBADMSG;
if (vlen >= 4 && v[1] != 0 && v[2] == ASN1_BOOL && v[3] == 1)
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_CA;
return 0;
}

return 0;
}

Expand Down
6 changes: 3 additions & 3 deletions drivers/char/tpm/eventlog/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ static int tpm_bios_measurements_open(struct inode *inode,
inode_unlock(inode);
return -ENODEV;
}
chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
chip_seqops = inode->i_private;
seqops = chip_seqops->seqops;
chip = chip_seqops->chip;
get_device(&chip->dev);
Expand All @@ -55,8 +55,8 @@ static int tpm_bios_measurements_open(struct inode *inode,
static int tpm_bios_measurements_release(struct inode *inode,
struct file *file)
{
struct seq_file *seq = (struct seq_file *)file->private_data;
struct tpm_chip *chip = (struct tpm_chip *)seq->private;
struct seq_file *seq = file->private_data;
struct tpm_chip *chip = seq->private;

put_device(&chip->dev);

Expand Down
4 changes: 2 additions & 2 deletions drivers/char/tpm/st33zp24/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@ static const struct i2c_device_id st33zp24_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id);

static const struct of_device_id of_st33zp24_i2c_match[] = {
static const struct of_device_id of_st33zp24_i2c_match[] __maybe_unused = {
{ .compatible = "st,st33zp24-i2c", },
{}
};
MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match);

static const struct acpi_device_id st33zp24_i2c_acpi_match[] = {
static const struct acpi_device_id st33zp24_i2c_acpi_match[] __maybe_unused = {
{"SMO3324"},
{}
};
Expand Down
4 changes: 2 additions & 2 deletions drivers/char/tpm/st33zp24/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,13 @@ static const struct spi_device_id st33zp24_spi_id[] = {
};
MODULE_DEVICE_TABLE(spi, st33zp24_spi_id);

static const struct of_device_id of_st33zp24_spi_match[] = {
static const struct of_device_id of_st33zp24_spi_match[] __maybe_unused = {
{ .compatible = "st,st33zp24-spi", },
{}
};
MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match);

static const struct acpi_device_id st33zp24_spi_acpi_match[] = {
static const struct acpi_device_id st33zp24_spi_acpi_match[] __maybe_unused = {
{"SMO3324"},
{}
};
Expand Down
41 changes: 26 additions & 15 deletions drivers/char/tpm/tpm-chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,30 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip)
return rc;
}

/*
* tpm_chip_startup() - performs auto startup and allocates the PCRs
* @chip: TPM chip to use.
*/
int tpm_chip_startup(struct tpm_chip *chip)
{
int rc;

rc = tpm_chip_start(chip);
if (rc)
return rc;

rc = tpm_auto_startup(chip);
if (rc)
goto stop;

rc = tpm_get_pcr_allocation(chip);
stop:
tpm_chip_stop(chip);

return rc;
}
EXPORT_SYMBOL_GPL(tpm_chip_startup);

/*
* tpm_chip_register() - create a character device for the TPM chip
* @chip: TPM chip to use.
Expand All @@ -620,20 +644,6 @@ int tpm_chip_register(struct tpm_chip *chip)
{
int rc;

rc = tpm_chip_start(chip);
if (rc)
return rc;
rc = tpm_auto_startup(chip);
if (rc) {
tpm_chip_stop(chip);
return rc;
}

rc = tpm_get_pcr_allocation(chip);
tpm_chip_stop(chip);
if (rc)
return rc;

tpm_sysfs_add_device(chip);

tpm_bios_log_setup(chip);
Expand Down Expand Up @@ -682,7 +692,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
void tpm_chip_unregister(struct tpm_chip *chip)
{
tpm_del_legacy_sysfs(chip);
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip))
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip) &&
!tpm_amd_is_rng_defective(chip))
hwrng_unregister(&chip->hwrng);
tpm_bios_log_teardown(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip))
Expand Down
1 change: 1 addition & 0 deletions drivers/char/tpm/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ static inline void tpm_msleep(unsigned int delay_msec)
delay_msec * 1000);
};

int tpm_chip_startup(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);
Expand Down
6 changes: 3 additions & 3 deletions drivers/char/tpm/tpm_ftpm_tee.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,11 @@ static int ftpm_tee_remove(struct device *dev)
return 0;
}

static int ftpm_plat_tee_remove(struct platform_device *pdev)
static void ftpm_plat_tee_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;

return ftpm_tee_remove(dev);
ftpm_tee_remove(dev);
}

/**
Expand Down Expand Up @@ -367,7 +367,7 @@ static struct platform_driver ftpm_tee_plat_driver = {
},
.shutdown = ftpm_plat_tee_shutdown,
.probe = ftpm_plat_tee_probe,
.remove = ftpm_plat_tee_remove,
.remove_new = ftpm_plat_tee_remove,
};

/* UUID of the fTPM TA */
Expand Down
51 changes: 44 additions & 7 deletions drivers/char/tpm/tpm_tis.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,45 @@ static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *da
return container_of(data, struct tpm_tis_tcg_phy, priv);
}

#ifdef CONFIG_PREEMPT_RT
/*
* Flush previous write operations with a dummy read operation to the
* TPM MMIO base address.
*/
static inline void tpm_tis_flush(void __iomem *iobase)
{
ioread8(iobase + TPM_ACCESS(0));
}
#else
#define tpm_tis_flush(iobase) do { } while (0)
#endif

/*
* Write a byte word to the TPM MMIO address, and flush the write queue.
* The flush ensures that the data is sent immediately over the bus and not
* aggregated with further requests and transferred later in a batch. The large
* write requests can lead to unwanted latency spikes by blocking the CPU until
* the complete batch has been transferred.
*/
static inline void tpm_tis_iowrite8(u8 b, void __iomem *iobase, u32 addr)
{
iowrite8(b, iobase + addr);
tpm_tis_flush(iobase);
}

/*
* Write a 32-bit word to the TPM MMIO address, and flush the write queue.
* The flush ensures that the data is sent immediately over the bus and not
* aggregated with further requests and transferred later in a batch. The large
* write requests can lead to unwanted latency spikes by blocking the CPU until
* the complete batch has been transferred.
*/
static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr)
{
iowrite32(b, iobase + addr);
tpm_tis_flush(iobase);
}

static int interrupts = -1;
module_param(interrupts, int, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
Expand Down Expand Up @@ -186,12 +225,12 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
switch (io_mode) {
case TPM_TIS_PHYS_8:
while (len--)
iowrite8(*value++, phy->iobase + addr);
tpm_tis_iowrite8(*value++, phy->iobase, addr);
break;
case TPM_TIS_PHYS_16:
return -EINVAL;
case TPM_TIS_PHYS_32:
iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase + addr);
tpm_tis_iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase, addr);
break;
}

Expand Down Expand Up @@ -227,7 +266,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
irq = tpm_info->irq;

if (itpm || is_itpm(ACPI_COMPANION(dev)))
phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND;
set_bit(TPM_TIS_ITPM_WORKAROUND, &phy->priv.flags);

return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
ACPI_HANDLE(dev));
Expand Down Expand Up @@ -324,14 +363,12 @@ static int tpm_tis_plat_probe(struct platform_device *pdev)
return tpm_tis_init(&pdev->dev, &tpm_info);
}

static int tpm_tis_plat_remove(struct platform_device *pdev)
static void tpm_tis_plat_remove(struct platform_device *pdev)
{
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);

tpm_chip_unregister(chip);
tpm_tis_remove(chip);

return 0;
}

#ifdef CONFIG_OF
Expand All @@ -344,7 +381,7 @@ MODULE_DEVICE_TABLE(of, tis_of_platform_match);

static struct platform_driver tis_drv = {
.probe = tpm_tis_plat_probe,
.remove = tpm_tis_plat_remove,
.remove_new = tpm_tis_plat_remove,
.driver = {
.name = "tpm_tis",
.pm = &tpm_tis_pm,
Expand Down
Loading

0 comments on commit 1a0beef

Please sign in to comment.