diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2024-04-29 13:42:57 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2024-04-29 13:42:57 +1000 |
commit | 4f8ab65726cde1b40a9f693e1a8c5e145515ef56 (patch) | |
tree | 073c0d7ba05b8d87cfc0495bd5c3d0ff0445d49d | |
parent | 1f2a8a7b26dc26ed6961b206da89d0c7799b13a3 (diff) | |
parent | 3c6e94beeacd4d0141236fe5821a89867412af5f (diff) | |
download | linux-next-history-4f8ab65726cde1b40a9f693e1a8c5e145515ef56.tar.gz |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd.git
Notice: this object is not reachable from any branch.
Notice: this object is not reachable from any branch.
-rw-r--r-- | Documentation/security/tpm/index.rst | 1 | ||||
-rw-r--r-- | Documentation/security/tpm/tpm_tis.rst | 46 | ||||
-rw-r--r-- | drivers/char/tpm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/char/tpm/eventlog/acpi.c | 1 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_infineon.c | 16 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.c | 19 | ||||
-rw-r--r-- | security/keys/gc.c | 8 | ||||
-rw-r--r-- | security/keys/key.c | 35 | ||||
-rw-r--r-- | security/keys/keyctl.c | 11 |
9 files changed, 98 insertions, 40 deletions
diff --git a/Documentation/security/tpm/index.rst b/Documentation/security/tpm/index.rst index fc40e9f23c8599..f27a17f60a9602 100644 --- a/Documentation/security/tpm/index.rst +++ b/Documentation/security/tpm/index.rst @@ -5,6 +5,7 @@ Trusted Platform Module documentation .. toctree:: tpm_event_log + tpm_tis tpm_vtpm_proxy xen-tpmfront tpm_ftpm_tee diff --git a/Documentation/security/tpm/tpm_tis.rst b/Documentation/security/tpm/tpm_tis.rst new file mode 100644 index 00000000000000..b9637f2956381e --- /dev/null +++ b/Documentation/security/tpm/tpm_tis.rst @@ -0,0 +1,46 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================= +TPM FIFO interface driver +========================= + +TCG PTP Specification defines two interface types: FIFO and CRB. The former is +based on sequenced read and write operations, and the latter is based on a +buffer containing the full command or response. + +FIFO (First-In-First-Out) interface is used by the tpm_tis_core dependent +drivers. Originally Linux had only a driver called tpm_tis, which covered +memory mapped (aka MMIO) interface but it was later on extended to cover other +physical interfaces supported by the TCG standard. + +For historical reasons above the original MMIO driver is called tpm_tis and the +framework for FIFO drivers is named as tpm_tis_core. The postfix "tis" in +tpm_tis comes from the TPM Interface Specification, which is the hardware +interface specification for TPM 1.x chips. + +Communication is based on a 20 KiB buffer shared by the TPM chip through a +hardware bus or memory map, depending on the physical wiring. The buffer is +further split into five equal-size 4 KiB buffers, which provide equivalent +sets of registers for communication between the CPU and TPM. These +communication endpoints are called localities in the TCG terminology. + +When the kernel wants to send commands to the TPM chip, it first reserves +locality 0 by setting the requestUse bit in the TPM_ACCESS register. The bit is +cleared by the chip when the access is granted. Once it completes its +communication, the kernel writes the TPM_ACCESS.activeLocality bit. This +informs the chip that the locality has been relinquished. + +Pending localities are served in order by the chip in descending order, one at +a time: + +- Locality 0 has the lowest priority. +- Locality 5 has the highest priority. + +Further information on the purpose and meaning of the localities can be found +in section 3.2 of the TCG PC Client Platform TPM Profile Specification. + +References +========== + +TCG PC Client Platform TPM Profile (PTP) Specification +https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 927088b2c3d3f2..418c9ed59ffde7 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -149,6 +149,7 @@ config TCG_NSC config TCG_ATMEL tristate "Atmel TPM Interface" depends on PPC64 || HAS_IOPORT_MAP + depends on HAS_IOPORT help If you have a TPM security chip from Atmel say Yes and it will be accessible from within Linux. To compile this driver diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c index bd757d836c5cf9..69533d0bfb51e8 100644 --- a/drivers/char/tpm/eventlog/acpi.c +++ b/drivers/char/tpm/eventlog/acpi.c @@ -142,7 +142,6 @@ int tpm_read_log_acpi(struct tpm_chip *chip) log->bios_event_log_end = log->bios_event_log + len; - ret = -EIO; virt = acpi_os_map_iomem(start, len); if (!virt) { dev_warn(&chip->dev, "%s: Failed to map ACPI memory\n", __func__); diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 9c924a1440a913..99c6e565ec8d53 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -26,7 +26,9 @@ #define TPM_MAX_TRIES 5000 #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 +#ifdef CONFIG_HAS_IOPORT #define TPM_INF_IO_PORT 0x0 +#endif #define TPM_INF_IO_MEM 0x1 #define TPM_INF_ADDR 0x0 @@ -51,34 +53,40 @@ static struct tpm_inf_dev tpm_dev; static inline void tpm_data_out(unsigned char data, unsigned char offset) { +#ifdef CONFIG_HAS_IOPORT if (tpm_dev.iotype == TPM_INF_IO_PORT) outb(data, tpm_dev.data_regs + offset); else +#endif writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset); } static inline unsigned char tpm_data_in(unsigned char offset) { +#ifdef CONFIG_HAS_IOPORT if (tpm_dev.iotype == TPM_INF_IO_PORT) return inb(tpm_dev.data_regs + offset); - else - return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset); +#endif + return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset); } static inline void tpm_config_out(unsigned char data, unsigned char offset) { +#ifdef CONFIG_HAS_IOPORT if (tpm_dev.iotype == TPM_INF_IO_PORT) outb(data, tpm_dev.config_port + offset); else +#endif writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset); } static inline unsigned char tpm_config_in(unsigned char offset) { +#ifdef CONFIG_HAS_IOPORT if (tpm_dev.iotype == TPM_INF_IO_PORT) return inb(tpm_dev.config_port + offset); - else - return readb(tpm_dev.mem_base + tpm_dev.index_off + offset); +#endif + return readb(tpm_dev.mem_base + tpm_dev.index_off + offset); } /* TPM header definitions */ diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 714070ebb6e7a2..176cd8dbf1db2c 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -1057,11 +1057,6 @@ static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value) clkrun_val &= ~LPC_CLKRUN_EN; iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); - /* - * Write any random value on port 0x80 which is on LPC, to make - * sure LPC clock is running before sending any TPM command. - */ - outb(0xCC, 0x80); } else { data->clkrun_enabled--; if (data->clkrun_enabled) @@ -1072,13 +1067,15 @@ static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value) /* Enable LPC CLKRUN# */ clkrun_val |= LPC_CLKRUN_EN; iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); - - /* - * Write any random value on port 0x80 which is on LPC, to make - * sure LPC clock is running before sending any TPM command. - */ - outb(0xCC, 0x80); } + +#ifdef CONFIG_HAS_IOPORT + /* + * Write any random value on port 0x80 which is on LPC, to make + * sure LPC clock is running before sending any TPM command. + */ + outb(0xCC, 0x80); +#endif } static const struct tpm_class_ops tpm_tis = { diff --git a/security/keys/gc.c b/security/keys/gc.c index eaddaceda14eab..7d687b0962b146 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -155,14 +155,6 @@ static noinline void key_gc_unused_keys(struct list_head *keys) security_key_free(key); - /* deal with the user's key tracking and quota */ - if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { - spin_lock(&key->user->lock); - key->user->qnkeys--; - key->user->qnbytes -= key->quotalen; - spin_unlock(&key->user->lock); - } - atomic_dec(&key->user->nkeys); if (state != KEY_IS_UNINSTANTIATED) atomic_dec(&key->user->nikeys); diff --git a/security/keys/key.c b/security/keys/key.c index 5607900383298f..3d7d185019d30a 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -230,6 +230,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, struct key *key; size_t desclen, quotalen; int ret; + unsigned long irqflags; key = ERR_PTR(-EINVAL); if (!desc || !*desc) @@ -259,7 +260,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ? key_quota_root_maxbytes : key_quota_maxbytes; - spin_lock(&user->lock); + spin_lock_irqsave(&user->lock, irqflags); if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { if (user->qnkeys + 1 > maxkeys || user->qnbytes + quotalen > maxbytes || @@ -269,7 +270,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, user->qnkeys++; user->qnbytes += quotalen; - spin_unlock(&user->lock); + spin_unlock_irqrestore(&user->lock, irqflags); } /* allocate and initialise the key and its description */ @@ -327,10 +328,10 @@ security_error: kfree(key->description); kmem_cache_free(key_jar, key); if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { - spin_lock(&user->lock); + spin_lock_irqsave(&user->lock, irqflags); user->qnkeys--; user->qnbytes -= quotalen; - spin_unlock(&user->lock); + spin_unlock_irqrestore(&user->lock, irqflags); } key_user_put(user); key = ERR_PTR(ret); @@ -340,10 +341,10 @@ no_memory_3: kmem_cache_free(key_jar, key); no_memory_2: if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { - spin_lock(&user->lock); + spin_lock_irqsave(&user->lock, irqflags); user->qnkeys--; user->qnbytes -= quotalen; - spin_unlock(&user->lock); + spin_unlock_irqrestore(&user->lock, irqflags); } key_user_put(user); no_memory_1: @@ -351,7 +352,7 @@ no_memory_1: goto error; no_quota: - spin_unlock(&user->lock); + spin_unlock_irqrestore(&user->lock, irqflags); key_user_put(user); key = ERR_PTR(-EDQUOT); goto error; @@ -380,8 +381,9 @@ int key_payload_reserve(struct key *key, size_t datalen) if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ? key_quota_root_maxbytes : key_quota_maxbytes; + unsigned long flags; - spin_lock(&key->user->lock); + spin_lock_irqsave(&key->user->lock, flags); if (delta > 0 && (key->user->qnbytes + delta > maxbytes || @@ -392,7 +394,7 @@ int key_payload_reserve(struct key *key, size_t datalen) key->user->qnbytes += delta; key->quotalen += delta; } - spin_unlock(&key->user->lock); + spin_unlock_irqrestore(&key->user->lock, flags); } /* change the recorded data length if that didn't generate an error */ @@ -463,7 +465,8 @@ static int __key_instantiate_and_link(struct key *key, if (authkey) key_invalidate(authkey); - key_set_expiry(key, prep->expiry); + if (prep->expiry != TIME64_MAX) + key_set_expiry(key, prep->expiry); } } @@ -645,8 +648,18 @@ void key_put(struct key *key) if (key) { key_check(key); - if (refcount_dec_and_test(&key->usage)) + if (refcount_dec_and_test(&key->usage)) { + unsigned long flags; + + /* deal with the user's key tracking and quota */ + if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { + spin_lock_irqsave(&key->user->lock, flags); + key->user->qnkeys--; + key->user->qnbytes -= key->quotalen; + spin_unlock_irqrestore(&key->user->lock, flags); + } schedule_work(&key_gc_work); + } } } EXPORT_SYMBOL(key_put); diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 10ba439968f744..4bc3e9398ee3d9 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -954,6 +954,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) long ret; kuid_t uid; kgid_t gid; + unsigned long flags; uid = make_kuid(current_user_ns(), user); gid = make_kgid(current_user_ns(), group); @@ -1010,7 +1011,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ? key_quota_root_maxbytes : key_quota_maxbytes; - spin_lock(&newowner->lock); + spin_lock_irqsave(&newowner->lock, flags); if (newowner->qnkeys + 1 > maxkeys || newowner->qnbytes + key->quotalen > maxbytes || newowner->qnbytes + key->quotalen < @@ -1019,12 +1020,12 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) newowner->qnkeys++; newowner->qnbytes += key->quotalen; - spin_unlock(&newowner->lock); + spin_unlock_irqrestore(&newowner->lock, flags); - spin_lock(&key->user->lock); + spin_lock_irqsave(&key->user->lock, flags); key->user->qnkeys--; key->user->qnbytes -= key->quotalen; - spin_unlock(&key->user->lock); + spin_unlock_irqrestore(&key->user->lock, flags); } atomic_dec(&key->user->nkeys); @@ -1056,7 +1057,7 @@ error: return ret; quota_overrun: - spin_unlock(&newowner->lock); + spin_unlock_irqrestore(&newowner->lock, flags); zapowner = newowner; ret = -EDQUOT; goto error_put; |