From d1bd4a792d3961a04e6154118816b00167aad91a Mon Sep 17 00:00:00 2001 From: Josh Zimmerman Date: Sun, 25 Jun 2017 14:53:24 -0700 Subject: tpm: Issue a TPM2_Shutdown for TPM2 devices. If a TPM2 loses power without a TPM2_Shutdown command being issued (a "disorderly reboot"), it may lose some state that has yet to be persisted to NVRam, and will increment the DA counter. After the DA counter gets sufficiently large, the TPM will lock the user out. NOTE: This only changes behavior on TPM2 devices. Since TPM1 uses sysfs, and sysfs relies on implicit locking on chip->ops, it is not safe to allow this code to run in TPM1, or to add sysfs support to TPM2, until that locking is made explicit. Signed-off-by: Josh Zimmerman Cc: stable@vger.kernel.org Fixes: 74d6b3ceaa17 ("tpm: fix suspend/resume paths for TPM 2.0") Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm-chip.c | 34 ++++++++++++++++++++++++++++++++++ drivers/char/tpm/tpm-sysfs.c | 3 +++ 2 files changed, 37 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 322b8a51ffc6..67ec9d3d04f5 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -142,6 +142,39 @@ static void tpm_devs_release(struct device *dev) put_device(&chip->dev); } +/** + * tpm_class_shutdown() - prepare the TPM device for loss of power. + * @dev: device to which the chip is associated. + * + * Issues a TPM2_Shutdown command prior to loss of power, as required by the + * TPM 2.0 spec. + * Then, calls bus- and device- specific shutdown code. + * + * XXX: This codepath relies on the fact that sysfs is not enabled for + * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2 + * has sysfs support enabled before TPM sysfs's implicit locking is fixed. + */ +static int tpm_class_shutdown(struct device *dev) +{ + struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); + + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + down_write(&chip->ops_sem); + tpm2_shutdown(chip, TPM2_SU_CLEAR); + chip->ops = NULL; + up_write(&chip->ops_sem); + } + /* Allow bus- and device-specific code to run. Note: since chip->ops + * is NULL, more-specific shutdown code will not be able to issue TPM + * commands. + */ + if (dev->bus && dev->bus->shutdown) + dev->bus->shutdown(dev); + else if (dev->driver && dev->driver->shutdown) + dev->driver->shutdown(dev); + return 0; +} + /** * tpm_chip_alloc() - allocate a new struct tpm_chip instance * @pdev: device to which the chip is associated @@ -181,6 +214,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, device_initialize(&chip->devs); chip->dev.class = tpm_class; + chip->dev.class->shutdown = tpm_class_shutdown; chip->dev.release = tpm_dev_release; chip->dev.parent = pdev; chip->dev.groups = chip->groups; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 4bd0997cfa2d..938d03ce30fe 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -294,6 +294,9 @@ static const struct attribute_group tpm_dev_group = { void tpm_sysfs_add_device(struct tpm_chip *chip) { + /* XXX: If you wish to remove this restriction, you must first update + * tpm_sysfs to explicitly lock chip->ops. + */ if (chip->flags & TPM_CHIP_FLAG_TPM2) return; -- cgit v1.2.3 From 13b47cfcfc60495cde216eef4c01040d76174cbe Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 20 Jun 2017 11:38:02 +0200 Subject: tpm: fix a kernel memory leak in tpm-sysfs.c While cleaning up sysfs callback that prints EK we discovered a kernel memory leak. This commit fixes the issue by zeroing the buffer used for TPM command/response. The leak happen when we use either tpm_vtpm_proxy, tpm_ibmvtpm or xen-tpmfront. Cc: stable@vger.kernel.org Fixes: 0883743825e3 ("TPM: sysfs functions consolidation") Reported-by: Jason Gunthorpe Tested-by: Stefan Berger Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm-sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 938d03ce30fe..86f38d239476 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -36,9 +36,10 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, ssize_t err; int i, rc; char *str = buf; - struct tpm_chip *chip = to_tpm_chip(dev); + memset(&tpm_cmd, 0, sizeof(tpm_cmd)); + tpm_cmd.header.in = tpm_readpubek_header; err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE, READ_PUBEK_RESULT_MIN_BODY_SIZE, 0, -- cgit v1.2.3 From f128480f39166c0a4475b6937e7e3e148b1caecc Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 19 Jun 2017 08:27:17 +0200 Subject: tpm/tpm_crb: fix priv->cmd_size initialisation priv->cmd_size is never initialised if the cmd and rsp buffers reside at different addresses. Initialise it in the exit path of the function when rsp buffer has also been successfully allocated. Fixes: aa77ea0e43dc ("tpm/tpm_crb: cache cmd_size register value."). Signed-off-by: Manuel Lauss Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm_crb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index fe42c4a0d8d1..a4ac63a21d8a 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -514,11 +514,12 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, goto out; } - priv->cmd_size = cmd_size; - priv->rsp = priv->cmd; out: + if (!ret) + priv->cmd_size = cmd_size; + crb_go_idle(dev, priv); return ret; -- cgit v1.2.3 From 5e572cab92f0bb56ca1e6e5ee4d807663a7ccbad Mon Sep 17 00:00:00 2001 From: Azhar Shaikh Date: Sun, 18 Jun 2017 19:17:59 -0700 Subject: tpm: Enable CLKRUN protocol for Braswell systems To overcome a hardware limitation on Intel Braswell systems, disable CLKRUN protocol during TPM transactions and re-enable once the transaction is completed. Signed-off-by: Azhar Shaikh Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm.h | 4 ++ drivers/char/tpm/tpm_tis.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 1df0521138d3..cdd261383dea 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -36,6 +36,10 @@ #include #include +#ifdef CONFIG_X86 +#include +#endif + enum tpm_const { TPM_MINOR = 224, /* officially assigned */ TPM_BUFSIZE = 4096, diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index b14d4aa97af8..d97ce22267fb 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -132,13 +132,93 @@ static int check_acpi_tpm2(struct device *dev) } #endif +#ifdef CONFIG_X86 +#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000 +#define ILB_REMAP_SIZE 0x100 +#define LPC_CNTRL_REG_OFFSET 0x84 +#define LPC_CLKRUN_EN (1 << 2) + +void __iomem *ilb_base_addr; + +static inline bool is_bsw(void) +{ + return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0); +} + +/** + * tpm_platform_begin_xfer() - clear LPC CLKRUN_EN i.e. clocks will be running + */ +static void tpm_platform_begin_xfer(void) +{ + u32 clkrun_val; + + if (!is_bsw()) + return; + + clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET); + + /* Disable LPC CLKRUN# */ + clkrun_val &= ~LPC_CLKRUN_EN; + iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_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); + +} + +/** + * tpm_platform_end_xfer() - set LPC CLKRUN_EN i.e. clocks can be turned off + */ +static void tpm_platform_end_xfer(void) +{ + u32 clkrun_val; + + if (!is_bsw()) + return; + + clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET); + + /* Enable LPC CLKRUN# */ + clkrun_val |= LPC_CLKRUN_EN; + iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_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 +static inline bool is_bsw(void) +{ + return false; +} + +static void tpm_platform_begin_xfer(void) +{ +} + +static void tpm_platform_end_xfer(void) +{ +} +#endif + static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, u8 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); + tpm_platform_begin_xfer(); + while (len--) *result++ = ioread8(phy->iobase + addr); + + tpm_platform_end_xfer(); + return 0; } @@ -147,8 +227,13 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); + tpm_platform_begin_xfer(); + while (len--) iowrite8(*value++, phy->iobase + addr); + + tpm_platform_end_xfer(); + return 0; } @@ -156,7 +241,12 @@ static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); + tpm_platform_begin_xfer(); + *result = ioread16(phy->iobase + addr); + + tpm_platform_end_xfer(); + return 0; } @@ -164,7 +254,12 @@ static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); + tpm_platform_begin_xfer(); + *result = ioread32(phy->iobase + addr); + + tpm_platform_end_xfer(); + return 0; } @@ -172,7 +267,12 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); + tpm_platform_begin_xfer(); + iowrite32(value, phy->iobase + addr); + + tpm_platform_end_xfer(); + return 0; } @@ -360,6 +460,11 @@ static int __init init_tis(void) if (rc) goto err_force; +#ifdef CONFIG_X86 + if (is_bsw()) + ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR, + ILB_REMAP_SIZE); +#endif rc = platform_driver_register(&tis_drv); if (rc) goto err_platform; @@ -378,6 +483,10 @@ err_pnp: err_platform: if (force_pdev) platform_device_unregister(force_pdev); +#ifdef CONFIG_X86 + if (is_bsw()) + iounmap(ilb_base_addr); +#endif err_force: return rc; } @@ -387,6 +496,10 @@ static void __exit cleanup_tis(void) pnp_unregister_driver(&tis_pnp_driver); platform_driver_unregister(&tis_drv); +#ifdef CONFIG_X86 + if (is_bsw()) + iounmap(ilb_base_addr); +#endif if (force_pdev) platform_device_unregister(force_pdev); } -- cgit v1.2.3 From 19cbe4f680b48f950246815b891a66eeb67f7410 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Wed, 21 Jun 2017 09:31:34 +0200 Subject: tpm: consolidate the TPM startup code Consolidated all the "manual" TPM startup code to a single function in order to make code flows a bit cleaner and migrate to tpm_buf. Tested-by: Stefan Berger Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm-interface.c | 67 +++++++++++++++++++++++++--------------- drivers/char/tpm/tpm.h | 6 +--- drivers/char/tpm/tpm2-cmd.c | 32 +------------------ 3 files changed, 44 insertions(+), 61 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index d2b4df6d9894..3123a6e44687 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -540,6 +540,47 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, } EXPORT_SYMBOL_GPL(tpm_transmit_cmd); +#define TPM_ORD_STARTUP 153 +#define TPM_ST_CLEAR 1 + +/** + * tpm_startup - turn on the TPM + * @chip: TPM chip to use + * + * Normally the firmware should start the TPM. This function is provided as a + * workaround if this does not happen. A legal case for this could be for + * example when a TPM emulator is used. + * + * Return: same as tpm_transmit_cmd() + */ +int tpm_startup(struct tpm_chip *chip) +{ + struct tpm_buf buf; + int rc; + + dev_info(&chip->dev, "starting up the TPM manually\n"); + + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP); + if (rc < 0) + return rc; + + tpm_buf_append_u16(&buf, TPM2_SU_CLEAR); + } else { + rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP); + if (rc < 0) + return rc; + + tpm_buf_append_u16(&buf, TPM_ST_CLEAR); + } + + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, + "attempting to start the TPM"); + + tpm_buf_destroy(&buf); + return rc; +} + #define TPM_DIGEST_SIZE 20 #define TPM_RET_CODE_IDX 6 #define TPM_INTERNAL_RESULT_SIZE 200 @@ -586,27 +627,6 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, } EXPORT_SYMBOL_GPL(tpm_getcap); -#define TPM_ORD_STARTUP 153 -#define TPM_ST_CLEAR cpu_to_be16(1) -#define TPM_ST_STATE cpu_to_be16(2) -#define TPM_ST_DEACTIVATED cpu_to_be16(3) -static const struct tpm_input_header tpm_startup_header = { - .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), - .length = cpu_to_be32(12), - .ordinal = cpu_to_be32(TPM_ORD_STARTUP) -}; - -static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) -{ - struct tpm_cmd_t start_cmd; - start_cmd.header.in = tpm_startup_header; - - start_cmd.params.startup_in.startup_type = startup_type; - return tpm_transmit_cmd(chip, NULL, &start_cmd, - TPM_INTERNAL_RESULT_SIZE, 0, - 0, "attempting to start the TPM"); -} - int tpm_get_timeouts(struct tpm_chip *chip) { cap_t cap; @@ -636,10 +656,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL, sizeof(cap.timeout)); if (rc == TPM_ERR_INVALID_POSTINIT) { - /* The TPM is not started, we are the first to talk to it. - Execute a startup command. */ - dev_info(&chip->dev, "Issuing TPM_STARTUP\n"); - if (tpm_startup(chip, TPM_ST_CLEAR)) + if (tpm_startup(chip)) return rc; rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index cdd261383dea..71d661a60df2 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -382,10 +382,6 @@ struct tpm_getrandom_in { __be32 num_bytes; } __packed; -struct tpm_startup_in { - __be16 startup_type; -} __packed; - typedef union { struct tpm_readpubek_params_out readpubek_out; u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)]; @@ -393,7 +389,6 @@ typedef union { struct tpm_pcrread_out pcrread_out; struct tpm_getrandom_in getrandom_in; struct tpm_getrandom_out getrandom_out; - struct tpm_startup_in startup_in; } tpm_cmd_params; struct tpm_cmd_t { @@ -519,6 +514,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, const void *buf, size_t bufsiz, size_t min_rsp_body_length, unsigned int flags, const char *desc); +int tpm_startup(struct tpm_chip *chip); ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, const char *desc, size_t min_cap_length); int tpm_get_timeouts(struct tpm_chip *); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 3a9964326279..1962c9b15cd5 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -779,36 +779,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, } EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); -#define TPM2_STARTUP_IN_SIZE \ - (sizeof(struct tpm_input_header) + \ - sizeof(struct tpm2_startup_in)) - -static const struct tpm_input_header tpm2_startup_header = { - .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), - .length = cpu_to_be32(TPM2_STARTUP_IN_SIZE), - .ordinal = cpu_to_be32(TPM2_CC_STARTUP) -}; - -/** - * tpm2_startup() - send startup command to the TPM chip - * - * @chip: TPM chip to use. - * @startup_type: startup type. The value is either - * TPM_SU_CLEAR or TPM_SU_STATE. - * - * Return: Same as with tpm_transmit_cmd. - */ -static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) -{ - struct tpm2_cmd cmd; - - cmd.header.in = tpm2_startup_header; - - cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); - return tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, - "attempting to start the TPM"); -} - #define TPM2_SHUTDOWN_IN_SIZE \ (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_startup_in)) @@ -1150,7 +1120,7 @@ int tpm2_auto_startup(struct tpm_chip *chip) } if (rc == TPM2_RC_INITIALIZE) { - rc = tpm2_startup(chip, TPM2_SU_CLEAR); + rc = tpm_startup(chip); if (rc) goto out; -- cgit v1.2.3 From bc397085ca975d685c7a0b3a2984932eea4f6af0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 20 Jun 2017 11:22:02 +0100 Subject: tpm_tis: make ilb_base_addr static The pointer ilb_base_addr does not need to be in global scope, so make it static. Cleans up sparse warning: "symbol 'ilb_base_addr' was not declared. Should it be static?" Signed-off-by: Colin Ian King Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm_tis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index d97ce22267fb..7e55aa9ce680 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -138,7 +138,7 @@ static int check_acpi_tpm2(struct device *dev) #define LPC_CNTRL_REG_OFFSET 0x84 #define LPC_CLKRUN_EN (1 << 2) -void __iomem *ilb_base_addr; +static void __iomem *ilb_base_addr; static inline bool is_bsw(void) { -- cgit v1.2.3 From 91f7f3d773a469deeab3808d422363138295346e Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 23 Jun 2017 15:41:56 +0200 Subject: tpm: use tpm_buf functions in tpm2_pcr_read() tpm2_pcr_read() now builds the PCR read command buffer with tpm_buf functions. This solution is preferred to using a tpm2_cmd structure, as tpm_buf functions provide protection against buffer overflow. Signed-off-by: Roberto Sassu Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm2-cmd.c | 60 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 1962c9b15cd5..76b0c87b1288 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -42,17 +42,6 @@ struct tpm2_pcr_read_in { u8 pcr_select[TPM2_PCR_SELECT_MIN]; } __packed; -struct tpm2_pcr_read_out { - __be32 update_cnt; - __be32 pcr_selects_cnt; - __be16 hash_alg; - u8 pcr_select_size; - u8 pcr_select[TPM2_PCR_SELECT_MIN]; - __be32 digests_cnt; - __be16 digest_size; - u8 digest[TPM_DIGEST_SIZE]; -} __packed; - struct tpm2_get_tpm_pt_in { __be32 cap_id; __be32 property_id; @@ -80,7 +69,6 @@ union tpm2_cmd_params { struct tpm2_startup_in startup_in; struct tpm2_self_test_in selftest_in; struct tpm2_pcr_read_in pcrread_in; - struct tpm2_pcr_read_out pcrread_out; struct tpm2_get_tpm_pt_in get_tpm_pt_in; struct tpm2_get_tpm_pt_out get_tpm_pt_out; struct tpm2_get_random_in getrandom_in; @@ -231,15 +219,23 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_pcr_read_in)) -#define TPM2_PCR_READ_RESP_BODY_SIZE \ - sizeof(struct tpm2_pcr_read_out) - static const struct tpm_input_header tpm2_pcrread_header = { .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), .ordinal = cpu_to_be32(TPM2_CC_PCR_READ) }; +struct tpm2_pcr_read_out { + __be32 update_cnt; + __be32 pcr_selects_cnt; + __be16 hash_alg; + u8 pcr_select_size; + u8 pcr_select[TPM2_PCR_SELECT_MIN]; + __be32 digests_cnt; + __be16 digest_size; + u8 digest[]; +} __packed; + /** * tpm2_pcr_read() - read a PCR value * @chip: TPM chip to use. @@ -251,29 +247,33 @@ static const struct tpm_input_header tpm2_pcrread_header = { int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { int rc; - struct tpm2_cmd cmd; - u8 *buf; + struct tpm_buf buf; + struct tpm2_pcr_read_out *out; + u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0}; if (pcr_idx >= TPM2_PLATFORM_PCR) return -EINVAL; - cmd.header.in = tpm2_pcrread_header; - cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); - cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); - cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ); + if (rc) + return rc; - memset(cmd.params.pcrread_in.pcr_select, 0, - sizeof(cmd.params.pcrread_in.pcr_select)); - cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); + pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); - rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), - TPM2_PCR_READ_RESP_BODY_SIZE, - 0, "attempting to read a pcr value"); - if (rc == 0) { - buf = cmd.params.pcrread_out.digest; - memcpy(res_buf, buf, TPM_DIGEST_SIZE); + tpm_buf_append_u32(&buf, 1); + tpm_buf_append_u16(&buf, TPM2_ALG_SHA1); + tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN); + tpm_buf_append(&buf, (const unsigned char *)pcr_select, + sizeof(pcr_select)); + + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, + res_buf ? "attempting to read a pcr value" : NULL); + if (rc == 0 && res_buf) { + out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE]; + memcpy(res_buf, out->digest, SHA1_DIGEST_SIZE); } + tpm_buf_destroy(&buf); return rc; } -- cgit v1.2.3 From 28707bf221ce6914a3e414637c8ffc4d27e9648d Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Fri, 23 Jun 2017 15:41:57 +0200 Subject: tpm: use tpm2_pcr_read() in tpm2_do_selftest() tpm2_do_selftest() performs a PCR read during the TPM initialization phase. This patch replaces the PCR read code with a call to tpm2_pcr_read(). Signed-off-by: Roberto Sassu Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm2-cmd.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 76b0c87b1288..f7f34b2aa981 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -35,13 +35,6 @@ struct tpm2_self_test_in { u8 full_test; } __packed; -struct tpm2_pcr_read_in { - __be32 pcr_selects_cnt; - __be16 hash_alg; - u8 pcr_select_size; - u8 pcr_select[TPM2_PCR_SELECT_MIN]; -} __packed; - struct tpm2_get_tpm_pt_in { __be32 cap_id; __be32 property_id; @@ -68,7 +61,6 @@ struct tpm2_get_random_out { union tpm2_cmd_params { struct tpm2_startup_in startup_in; struct tpm2_self_test_in selftest_in; - struct tpm2_pcr_read_in pcrread_in; struct tpm2_get_tpm_pt_in get_tpm_pt_in; struct tpm2_get_tpm_pt_out get_tpm_pt_out; struct tpm2_get_random_in getrandom_in; @@ -215,16 +207,6 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { TPM_UNDEFINED /* 18f */ }; -#define TPM2_PCR_READ_IN_SIZE \ - (sizeof(struct tpm_input_header) + \ - sizeof(struct tpm2_pcr_read_in)) - -static const struct tpm_input_header tpm2_pcrread_header = { - .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), - .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), - .ordinal = cpu_to_be32(TPM2_CC_PCR_READ) -}; - struct tpm2_pcr_read_out { __be32 update_cnt; __be32 pcr_selects_cnt; @@ -898,7 +880,6 @@ static int tpm2_do_selftest(struct tpm_chip *chip) unsigned int loops; unsigned int delay_msec = 100; unsigned long duration; - struct tpm2_cmd cmd; int i; duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST); @@ -911,20 +892,10 @@ static int tpm2_do_selftest(struct tpm_chip *chip) for (i = 0; i < loops; i++) { /* Attempt to read a PCR value */ - cmd.header.in = tpm2_pcrread_header; - cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); - cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); - cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; - cmd.params.pcrread_in.pcr_select[0] = 0x01; - cmd.params.pcrread_in.pcr_select[1] = 0x00; - cmd.params.pcrread_in.pcr_select[2] = 0x00; - - rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, - NULL); + rc = tpm2_pcr_read(chip, 0, NULL); if (rc < 0) break; - rc = be32_to_cpu(cmd.header.out.return_code); if (rc != TPM2_RC_TESTING) break; -- cgit v1.2.3 From b5d0ebc99bf5d0801a5ecbe958caa3d68b8eaee8 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 27 Jun 2017 12:27:24 +0200 Subject: tpm: do not suspend/resume if power stays on The suspend/resume behavior of the TPM can be controlled by setting "powered-while-suspended" in the DTS. This is useful for the cases when hardware does not power-off the TPM. Signed-off-by: Sonny Rao Signed-off-by: Enric Balletbo i Serra Reviewed-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris --- drivers/char/tpm/tpm-interface.c | 3 +++ drivers/char/tpm/tpm.h | 1 + drivers/char/tpm/tpm_of.c | 3 +++ 3 files changed, 7 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3123a6e44687..fe597e6c55c4 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1119,6 +1119,9 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) + return 0; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { tpm2_shutdown(chip, TPM2_SU_STATE); return 0; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 71d661a60df2..04fbff2edbf3 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -174,6 +174,7 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_IRQ = BIT(2), TPM_CHIP_FLAG_VIRTUAL = BIT(3), TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), }; struct tpm_bios_log { diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index de57d4ac8901..aadb7f464076 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -36,6 +36,9 @@ int tpm_read_log_of(struct tpm_chip *chip) else return -ENODEV; + if (of_property_read_bool(np, "powered-while-suspended")) + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + sizep = of_get_property(np, "linux,sml-size", NULL); basep = of_get_property(np, "linux,sml-base", NULL); if (sizep == NULL && basep == NULL) -- cgit v1.2.3