diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-31 13:12:31 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-31 13:12:31 -0800 |
commit | ae0cb7be35fe6c7e8bcc816ec4185d0a37748cc1 (patch) | |
tree | 2453151c8d507502ce91c6827f3e8a35e1777996 /drivers/char | |
parent | 2a7149031457c5dd05f670737a9dd5d32524f145 (diff) | |
parent | ebceb1c87c0c482d47cb92dc3cc51d28f7387716 (diff) |
Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull tpm updates from James Morris:
- reduce polling delays in tpm_tis
- support retrieving TPM 2.0 Event Log through EFI before
ExitBootServices
- replace tpm-rng.c with a hwrng device managed by the driver for each
TPM device
- TPM resource manager synthesizes TPM_RC_COMMAND_CODE response instead
of returning -EINVAL for unknown TPM commands. This makes user space
more sound.
- CLKRUN fixes:
* Keep #CLKRUN disable through the entier TPM command/response flow
* Check whether #CLKRUN is enabled before disabling and enabling it
again because enabling it breaks PS/2 devices on a system where it
is disabled
* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
tpm: remove unused variables
tpm: remove unused data fields from I2C and OF device ID tables
tpm: only attempt to disable the LPC CLKRUN if is already enabled
tpm: follow coding style for variable declaration in tpm_tis_core_init()
tpm: delete the TPM_TIS_CLK_ENABLE flag
tpm: Update MAINTAINERS for Jason Gunthorpe
tpm: Keep CLKRUN enabled throughout the duration of transmit_cmd()
tpm_tis: Move ilb_base_addr to tpm_tis_data
tpm2-cmd: allow more attempts for selftest execution
tpm: return a TPM_RC_COMMAND_CODE response if command is not implemented
tpm: Move Linux RNG connection to hwrng
tpm: use struct tpm_chip for tpm_chip_find_get()
tpm: parse TPM event logs based on EFI table
efi: call get_event_log before ExitBootServices
tpm: add event log format version
tpm: rename event log provider files
tpm: move tpm_eventlog.h outside of drivers folder
tpm: use tpm_msleep() value as max delay
tpm: reduce tpm polling delay in tpm_tis_core
tpm: move wait_for_tpm_stat() to respective driver files
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/hw_random/Kconfig | 13 | ||||
-rw-r--r-- | drivers/char/hw_random/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/hw_random/tpm-rng.c | 50 | ||||
-rw-r--r-- | drivers/char/tpm/Kconfig | 11 | ||||
-rw-r--r-- | drivers/char/tpm/Makefile | 5 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 67 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 231 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 52 | ||||
-rw-r--r-- | drivers/char/tpm/tpm1_eventlog.c | 13 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 12 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2_eventlog.c | 2 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog.h | 138 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog_acpi.c (renamed from drivers/char/tpm/tpm_acpi.c) | 4 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog_efi.c | 66 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog_of.c (renamed from drivers/char/tpm/tpm_of.c) | 6 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_infineon.c | 27 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 108 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.c | 193 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.h | 16 | ||||
-rw-r--r-- | drivers/char/tpm/xen-tpmfront.c | 61 |
20 files changed, 563 insertions, 513 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index f6e3e5abc117..88044eda0ac6 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -306,19 +306,6 @@ config HW_RANDOM_POWERNV If unsure, say Y. -config HW_RANDOM_TPM - tristate "TPM HW Random Number Generator support" - depends on TCG_TPM - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator in the Trusted Platform Module - - To compile this driver as a module, choose M here: the - module will be called tpm-rng. - - If unsure, say Y. - config HW_RANDOM_HISI tristate "Hisilicon Random Number Generator support" depends on HW_RANDOM && ARCH_HISI diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index f3728d008fff..0ef05c61d9c8 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -27,7 +27,6 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o -obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o diff --git a/drivers/char/hw_random/tpm-rng.c b/drivers/char/hw_random/tpm-rng.c deleted file mode 100644 index d6d448266f07..000000000000 --- a/drivers/char/hw_random/tpm-rng.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 Kent Yoder IBM Corporation - * - * HWRNG interfaces to pull RNG data from a TPM - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/hw_random.h> -#include <linux/tpm.h> - -#define MODULE_NAME "tpm-rng" - -static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) -{ - return tpm_get_random(TPM_ANY_NUM, data, max); -} - -static struct hwrng tpm_rng = { - .name = MODULE_NAME, - .read = tpm_rng_read, -}; - -static int __init rng_init(void) -{ - return hwrng_register(&tpm_rng); -} -module_init(rng_init); - -static void __exit rng_exit(void) -{ - hwrng_unregister(&tpm_rng); -} -module_exit(rng_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Kent Yoder <key@linux.vnet.ibm.com>"); -MODULE_DESCRIPTION("RNG driver for TPM devices"); diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index a30352202f1f..18c81cbe4704 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -26,6 +26,17 @@ menuconfig TCG_TPM if TCG_TPM +config HW_RANDOM_TPM + bool "TPM HW Random Number Generator support" + depends on TCG_TPM && HW_RANDOM && !(TCG_TPM=y && HW_RANDOM=m) + default y + ---help--- + This setting exposes the TPM's Random Number Generator as a hwrng + device. This allows the kernel to collect randomness from the TPM at + boot, and provides the TPM randomines in /dev/hwrng. + + If unsure, say Y. + config TCG_TIS_CORE tristate ---help--- diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 34b4bcf46f43..acd758381c58 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -6,8 +6,9 @@ obj-$(CONFIG_TCG_TPM) += tpm.o tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \ tpm2-space.o -tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o -tpm-$(CONFIG_OF) += tpm_of.o +tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_eventlog_acpi.o +tpm-$(CONFIG_EFI) += tpm_eventlog_efi.o +tpm-$(CONFIG_OF) += tpm_eventlog_of.o obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o obj-$(CONFIG_TCG_TIS) += tpm_tis.o obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 0eca20c5a80c..0a62c19937b6 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -26,8 +26,9 @@ #include <linux/spinlock.h> #include <linux/freezer.h> #include <linux/major.h> +#include <linux/tpm_eventlog.h> +#include <linux/hw_random.h> #include "tpm.h" -#include "tpm_eventlog.h" DEFINE_IDR(dev_nums_idr); static DEFINE_MUTEX(idr_lock); @@ -80,21 +81,26 @@ void tpm_put_ops(struct tpm_chip *chip) EXPORT_SYMBOL_GPL(tpm_put_ops); /** - * tpm_chip_find_get() - return tpm_chip for a given chip number - * @chip_num: id to find + * tpm_chip_find_get() - find and reserve a TPM chip + * @chip: a &struct tpm_chip instance, %NULL for the default chip * - * The return'd chip has been tpm_try_get_ops'd and must be released via - * tpm_put_ops + * Finds a TPM chip and reserves its class device and operations. The chip must + * be released with tpm_chip_put_ops() after use. + * + * 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_chip_find_get(int chip_num) +struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip) { - struct tpm_chip *chip, *res = NULL; + struct tpm_chip *res = NULL; + int chip_num = 0; int chip_prev; mutex_lock(&idr_lock); - if (chip_num == TPM_ANY_NUM) { - chip_num = 0; + if (!chip) { do { chip_prev = chip_num; chip = idr_get_next(&dev_nums_idr, &chip_num); @@ -104,8 +110,7 @@ struct tpm_chip *tpm_chip_find_get(int chip_num) } } while (chip_prev != chip_num); } else { - chip = idr_find(&dev_nums_idr, chip_num); - if (chip && !tpm_try_get_ops(chip)) + if (!tpm_try_get_ops(chip)) res = chip; } @@ -387,6 +392,26 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) return 0; } + +static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); + + return tpm_get_random(chip, data, max); +} + +static int tpm_add_hwrng(struct tpm_chip *chip) +{ + if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + return 0; + + snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), + "tpm-rng-%d", chip->dev_num); + chip->hwrng.name = chip->hwrng_name; + chip->hwrng.read = tpm_hwrng_read; + return hwrng_register(&chip->hwrng); +} + /* * tpm_chip_register() - create a character device for the TPM chip * @chip: TPM chip to use. @@ -419,11 +444,13 @@ int tpm_chip_register(struct tpm_chip *chip) tpm_add_ppi(chip); + rc = tpm_add_hwrng(chip); + if (rc) + goto out_ppi; + rc = tpm_add_char_device(chip); - if (rc) { - tpm_bios_log_teardown(chip); - return rc; - } + if (rc) + goto out_hwrng; rc = tpm_add_legacy_sysfs(chip); if (rc) { @@ -432,6 +459,14 @@ int tpm_chip_register(struct tpm_chip *chip) } return 0; + +out_hwrng: + if (IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + hwrng_unregister(&chip->hwrng); +out_ppi: + tpm_bios_log_teardown(chip); + + return rc; } EXPORT_SYMBOL_GPL(tpm_chip_register); @@ -451,6 +486,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)) + hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2) cdev_device_del(&chip->cdevs, &chip->devs); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 1d6729be4cd6..76df4fbcf089 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -30,9 +30,9 @@ #include <linux/spinlock.h> #include <linux/freezer.h> #include <linux/pm_runtime.h> +#include <linux/tpm_eventlog.h> #include "tpm.h" -#include "tpm_eventlog.h" #define TPM_MAX_ORDINAL 243 #define TSC_MAX_ORDINAL 12 @@ -328,7 +328,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -static bool tpm_validate_command(struct tpm_chip *chip, +static int tpm_validate_command(struct tpm_chip *chip, struct tpm_space *space, const u8 *cmd, size_t len) @@ -340,10 +340,10 @@ static bool tpm_validate_command(struct tpm_chip *chip, unsigned int nr_handles; if (len < TPM_HEADER_SIZE) - return false; + return -EINVAL; if (!space) - return true; + return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) { cc = be32_to_cpu(header->ordinal); @@ -352,7 +352,7 @@ static bool tpm_validate_command(struct tpm_chip *chip, if (i < 0) { dev_dbg(&chip->dev, "0x%04X is an invalid command\n", cc); - return false; + return -EOPNOTSUPP; } attrs = chip->cc_attrs_tbl[i]; @@ -362,11 +362,11 @@ static bool tpm_validate_command(struct tpm_chip *chip, goto err_len; } - return true; + return 0; err_len: dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__, len); - return false; + return -EINVAL; } /** @@ -391,8 +391,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, unsigned long stop; bool need_locality; - if (!tpm_validate_command(chip, space, buf, bufsiz)) - return -EINVAL; + rc = tpm_validate_command(chip, space, buf, bufsiz); + if (rc == -EINVAL) + return rc; + /* + * If the command is not implemented by the TPM, synthesize a + * response with a TPM2_RC_COMMAND_CODE return for user-space. + */ + if (rc == -EOPNOTSUPP) { + header->length = cpu_to_be32(sizeof(*header)); + header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); + header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | + TSS2_RESMGR_TPM_RC_LAYER); + return bufsiz; + } if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; @@ -413,6 +425,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, if (chip->dev.parent) pm_runtime_get_sync(chip->dev.parent); + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; @@ -489,6 +504,9 @@ out: chip->locality = -1; } out_no_locality: + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + if (chip->dev.parent) pm_runtime_put_sync(chip->dev.parent); @@ -809,19 +827,20 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) } /** - * tpm_is_tpm2 - is the chip a TPM2 chip? - * @chip_num: tpm idx # or ANY + * tpm_is_tpm2 - do we a have a TPM2 chip? + * @chip: a &struct tpm_chip instance, %NULL for the default chip * - * Returns < 0 on error, and 1 or 0 on success depending whether the chip - * is a TPM2 chip. + * Return: + * 1 if we have a TPM2 chip. + * 0 if we don't have a TPM2 chip. + * A negative number for system errors (errno). */ -int tpm_is_tpm2(u32 chip_num) +int tpm_is_tpm2(struct tpm_chip *chip) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; @@ -833,23 +852,19 @@ int tpm_is_tpm2(u32 chip_num) EXPORT_SYMBOL_GPL(tpm_is_tpm2); /** - * tpm_pcr_read - read a pcr value - * @chip_num: tpm idx # or ANY - * @pcr_idx: pcr idx to retrieve - * @res_buf: TPM_PCR value - * size of res_buf is 20 bytes (or NULL if you don't care) + * tpm_pcr_read - read a PCR value from SHA1 bank + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @pcr_idx: the PCR to be retrieved + * @res_buf: the value of the PCR * - * The TPM driver should be built-in, but for whatever reason it - * isn't, protect against the chip disappearing, by incrementing - * the module usage count. + * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) +int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_pcr_read(chip, pcr_idx, res_buf); @@ -889,25 +904,26 @@ static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash, } /** - * tpm_pcr_extend - extend pcr value with hash - * @chip_num: tpm idx # or AN& - * @pcr_idx: pcr idx to extend - * @hash: hash value used to extend pcr value + * tpm_pcr_extend - extend a PCR value in SHA1 bank. + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @pcr_idx: the PCR to be retrieved + * @hash: the hash value used to extend the PCR value * - * The TPM driver should be built-in, but for whatever reason it - * isn't, protect against the chip disappearing, by incrementing - * the module usage count. + * Note: with TPM 2.0 extends also those banks with a known digest size to the + * cryto subsystem in order to prevent malicious use of those PCR banks. In the + * future we should dynamically determine digest sizes. + * + * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) +int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { int rc; - struct tpm_chip *chip; struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)]; u32 count = 0; int i; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -1019,82 +1035,29 @@ out: return rc; } -int tpm_send(u32 chip_num, void *cmd, size_t buflen) +/** + * tpm_send - send a TPM command + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @cmd: a TPM command buffer + * @buflen: the length of the TPM command buffer + * + * Return: same as with tpm_transmit_cmd() + */ +int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0, - "attempting tpm_cmd"); + "attempting to a send a command"); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_send); -static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, - bool check_cancel, bool *canceled) -{ - u8 status = chip->ops->status(chip); - - *canceled = false; - if ((status & mask) == mask) - return true; - if (check_cancel && chip->ops->req_canceled(chip, status)) { - *canceled = true; - return true; - } - return false; -} - -int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue, bool check_cancel) -{ - unsigned long stop; - long rc; - u8 status; - bool canceled = false; - - /* check current status */ - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - - stop = jiffies + timeout; - - if (chip->flags & TPM_CHIP_FLAG_IRQ) { -again: - timeout = stop - jiffies; - if ((long)timeout <= 0) - return -ETIME; - rc = wait_event_interruptible_timeout(*queue, - wait_for_tpm_stat_cond(chip, mask, check_cancel, - &canceled), - timeout); - if (rc > 0) { - if (canceled) - return -ECANCELED; - return 0; - } - if (rc == -ERESTARTSYS && freezing(current)) { - clear_thread_flag(TIF_SIGPENDING); - goto again; - } - } else { - do { - tpm_msleep(TPM_TIMEOUT); - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - } while (time_before(jiffies, stop)); - } - return -ETIME; -} -EXPORT_SYMBOL_GPL(wait_for_tpm_stat); - #define TPM_ORD_SAVESTATE 152 #define SAVESTATE_RESULT_SIZE 10 @@ -1187,16 +1150,15 @@ static const struct tpm_input_header tpm_getrandom_header = { }; /** - * tpm_get_random() - Get random bytes from the tpm's RNG - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @out: destination buffer for the random bytes - * @max: the max number of bytes to write to @out + * tpm_get_random() - get random bytes from the TPM's RNG + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @out: destination buffer for the random bytes + * @max: the max number of bytes to write to @out * - * Returns < 0 on error and the number of bytes read on success + * Return: same as with tpm_transmit_cmd() */ -int tpm_get_random(u32 chip_num, u8 *out, size_t max) +int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) { - struct tpm_chip *chip; struct tpm_cmd_t tpm_cmd; u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength; int err, total = 0, retries = 5; @@ -1205,8 +1167,8 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -1248,22 +1210,23 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) EXPORT_SYMBOL_GPL(tpm_get_random); /** - * tpm_seal_trusted() - seal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options - * @payload: the key data in clear and encrypted form + * tpm_seal_trusted() - seal a trusted key payload + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form * - * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips - * are supported. + * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in + * the keyring subsystem. + * + * Return: same as with tpm_transmit_cmd() */ -int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload, +int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + chip = tpm_chip_find_get(chip); + if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_seal_trusted(chip, payload, options); @@ -1275,21 +1238,23 @@ EXPORT_SYMBOL_GPL(tpm_seal_trusted); /** * tpm_unseal_trusted() - unseal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options - * @payload: the key data in clear and encrypted form + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form + * + * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in + * the keyring subsystem. * - * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips - * are supported. + * Return: same as with tpm_transmit_cmd() */ -int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload, +int tpm_unseal_trusted(struct tpm_chip *chip, + struct trusted_key_payload *payload, struct trusted_key_options *options) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + chip = tpm_chip_find_get(chip); + if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_unseal_trusted(chip, payload, options); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 528cffbd49d3..f895fba4e20d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/fs.h> +#include <linux/hw_random.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/platform_device.h> @@ -34,6 +35,7 @@ #include <linux/acpi.h> #include <linux/cdev.h> #include <linux/highmem.h> +#include <linux/tpm_eventlog.h> #include <crypto/hash_info.h> #ifdef CONFIG_X86 @@ -93,12 +95,17 @@ enum tpm2_structures { TPM2_ST_SESSIONS = 0x8002, }; +/* Indicates from what layer of the software stack the error comes from */ +#define TSS2_RC_LAYER_SHIFT 16 +#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT) + enum tpm2_return_codes { TPM2_RC_SUCCESS = 0x0000, TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ TPM2_RC_HANDLE = 0x008B, TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ TPM2_RC_DISABLED = 0x0120, + TPM2_RC_COMMAND_CODE = 0x0143, TPM2_RC_TESTING = 0x090A, /* RC_WARN */ TPM2_RC_REFERENCE_H0 = 0x0910, }; @@ -210,6 +217,9 @@ struct tpm_chip { int dev_num; /* /dev/tpm# */ unsigned long is_open; /* only one allowed */ + char hwrng_name[64]; + struct hwrng hwrng; + struct mutex tpm_mutex; /* tpm is processing */ unsigned long timeout_a; /* jiffies */ @@ -385,10 +395,6 @@ struct tpm_cmd_t { tpm_cmd_params params; } __packed; -struct tpm2_digest { - u16 alg_id; - u8 digest[SHA512_DIGEST_SIZE]; -} __packed; /* A string buffer type for constructing TPM commands. This is based on the * ideas of string buffer code in security/keys/trusted.h but is heap based @@ -512,16 +518,14 @@ int tpm_do_selftest(struct tpm_chip *chip); unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal); int tpm_pm_suspend(struct device *dev); int tpm_pm_resume(struct device *dev); -int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue, bool check_cancel); static inline void tpm_msleep(unsigned int delay_msec) { - usleep_range(delay_msec * 1000, - (delay_msec * 1000) + TPM_TIMEOUT_RANGE_US); + usleep_range((delay_msec * 1000) - TPM_TIMEOUT_RANGE_US, + delay_msec * 1000); }; -struct tpm_chip *tpm_chip_find_get(int chip_num); +struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip); __must_check int tpm_try_get_ops(struct tpm_chip *chip); void tpm_put_ops(struct tpm_chip *chip); @@ -575,4 +579,34 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, u8 *cmd); int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, u8 *buf, size_t *bufsiz); + +extern const struct seq_operations tpm2_binary_b_measurements_seqops; + +#if defined(CONFIG_ACPI) +int tpm_read_log_acpi(struct tpm_chip *chip); +#else +static inline int tpm_read_log_acpi(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif +#if defined(CONFIG_OF) +int tpm_read_log_of(struct tpm_chip *chip); +#else +static inline int tpm_read_log_of(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif +#if defined(CONFIG_EFI) +int tpm_read_log_efi(struct tpm_chip *chip); +#else +static inline int tpm_read_log_efi(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif + +int tpm_bios_log_setup(struct tpm_chip *chip); +void tpm_bios_log_teardown(struct tpm_chip *chip); #endif diff --git a/drivers/char/tpm/tpm1_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c index 9a8605e500b5..add798bd69d0 100644 --- a/drivers/char/tpm/tpm1_eventlog.c +++ b/drivers/char/tpm/tpm1_eventlog.c @@ -21,13 +21,14 @@ */ #include <linux/seq_file.h> +#include <linux/efi.h> #include <linux/fs.h> #include <linux/security.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/tpm_eventlog.h> #include "tpm.h" -#include "tpm_eventlog.h" static const char* tcpa_event_type_strings[] = { @@ -371,6 +372,10 @@ static int tpm_read_log(struct tpm_chip *chip) if (rc != -ENODEV) return rc; + rc = tpm_read_log_efi(chip); + if (rc != -ENODEV) + return rc; + return tpm_read_log_of(chip); } @@ -388,11 +393,13 @@ int tpm_bios_log_setup(struct tpm_chip *chip) { const char *name = dev_name(&chip->dev); unsigned int cnt; + int log_version; int rc = 0; rc = tpm_read_log(chip); - if (rc) + if (rc < 0) return rc; + log_version = rc; cnt = 0; chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); @@ -404,7 +411,7 @@ int tpm_bios_log_setup(struct tpm_chip *chip) cnt++; chip->bin_log_seqops.chip = chip; - if (chip->flags & TPM_CHIP_FLAG_TPM2) + if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) chip->bin_log_seqops.seqops = &tpm2_binary_b_measurements_seqops; else diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index f40d20671a78..c17e75348a99 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -849,28 +849,26 @@ static const struct tpm_input_header tpm2_selftest_header = { static int tpm2_do_selftest(struct tpm_chip *chip) { int rc; - unsigned int delay_msec = 20; + unsigned int delay_msec = 10; long duration; struct tpm2_cmd cmd; duration = jiffies_to_msecs( tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST)); - while (duration > 0) { + while (1) { cmd.header.in = tpm2_selftest_header; cmd.params.selftest_in.full_test = 0; rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0, "continue selftest"); - if (rc != TPM2_RC_TESTING) + if (rc != TPM2_RC_TESTING || delay_msec >= duration) break; - tpm_msleep(delay_msec); - duration -= delay_msec; - - /* wait longer the next round */ + /* wait longer than before */ delay_msec *= 2; + tpm_msleep(delay_msec); } return rc; diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c index 34a8afa69138..1ce4411292ba 100644 --- a/drivers/char/tpm/tpm2_eventlog.c +++ b/drivers/char/tpm/tpm2_eventlog.c @@ -21,9 +21,9 @@ #include <linux/security.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/tpm_eventlog.h> #include "tpm.h" -#include "tpm_eventlog.h" /* * calc_tpm2_event_size() - calculate the event size, where event diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h deleted file mode 100644 index 204466cc4d05..000000000000 --- a/drivers/char/tpm/tpm_eventlog.h +++ /dev/null @@ -1,138 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __TPM_EVENTLOG_H__ -#define __TPM_EVENTLOG_H__ - -#include <crypto/hash_info.h> - -#define TCG_EVENT_NAME_LEN_MAX 255 -#define MAX_TEXT_EVENT 1000 /* Max event string length */ -#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ -#define TPM2_ACTIVE_PCR_BANKS 3 - -#ifdef CONFIG_PPC64 -#define do_endian_conversion(x) be32_to_cpu(x) -#else -#define do_endian_conversion(x) x -#endif - -enum bios_pla |