From cc26c6ef58c781473090ce45e17e4b5ff7bd8b2a Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 5 Jun 2018 22:22:58 +0300 Subject: tpm: migrate tpm2_shutdown() to use struct tpm_buf In order to make struct tpm_buf the first class object for constructing TPM commands, migrated tpm2_shutdown() to use it. Signed-off-by: Jarkko Sakkinen Reviewed-by: Nayna Jain Tested-by: Nayna Jain Reviewed-by: Jerry Snitselaar --- drivers/char/tpm/tpm2-cmd.c | 47 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 32 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index d31b09099216..026fec4e1800 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -27,10 +27,6 @@ enum tpm2_session_attributes { TPM2_SA_CONTINUE_SESSION = BIT(0), }; -struct tpm2_startup_in { - __be16 startup_type; -} __packed; - struct tpm2_get_tpm_pt_in { __be32 cap_id; __be32 property_id; @@ -55,7 +51,6 @@ struct tpm2_get_random_out { } __packed; union tpm2_cmd_params { - struct tpm2_startup_in startup_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; @@ -762,40 +757,28 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, } EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); -#define TPM2_SHUTDOWN_IN_SIZE \ - (sizeof(struct tpm_input_header) + \ - sizeof(struct tpm2_startup_in)) - -static const struct tpm_input_header tpm2_shutdown_header = { - .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), - .length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE), - .ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN) -}; - /** - * tpm2_shutdown() - send shutdown command to the TPM chip + * tpm2_shutdown() - send a TPM shutdown command * - * @chip: TPM chip to use. - * @shutdown_type: shutdown type. The value is either - * TPM_SU_CLEAR or TPM_SU_STATE. + * Sends a TPM shutdown command. The shutdown command is used in call + * sites where the system is going down. If it fails, there is not much + * that can be done except print an error message. + * + * @chip: a &tpm_chip instance + * @shutdown_type: TPM_SU_CLEAR or TPM_SU_STATE. */ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) { - struct tpm2_cmd cmd; + struct tpm_buf buf; int rc; - cmd.header.in = tpm2_shutdown_header; - cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); - - rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, - "stopping the TPM"); - - /* In places where shutdown command is sent there's no much we can do - * except print the error code on a system failure. - */ - if (rc < 0 && rc != -EPIPE) - dev_warn(&chip->dev, "transmit returned %d while stopping the TPM", - rc); + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN); + if (rc) + return; + tpm_buf_append_u16(&buf, shutdown_type); + tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, + "stopping the TPM"); + tpm_buf_destroy(&buf); } /* -- cgit v1.2.3 From 94e266ba1fa344631dca424b7c83370c8c22983d Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 26 Mar 2018 15:14:04 +0300 Subject: tpm: migrate tpm2_probe() to use struct tpm_buf In order to make struct tpm_buf the first class object for constructing TPM commands, migrate tpm2_probe() to use it. Signed-off-by: Jarkko Sakkinen Acked-by: Jay Freyensee Reviewed-by: Nayna Jain Tested-by: Nayna Jain Reviewed-by: Jerry Snitselaar --- drivers/char/tpm/tpm2-cmd.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 026fec4e1800..b82e2b141754 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -846,31 +846,37 @@ static int tpm2_do_selftest(struct tpm_chip *chip) } /** - * tpm2_probe() - probe TPM 2.0 - * @chip: TPM chip to use + * tpm2_probe() - probe for the TPM 2.0 protocol + * @chip: a &tpm_chip instance * - * Return: < 0 error and 0 on success. + * Send an idempotent TPM 2.0 command and see whether there is TPM2 chip in the + * other end based on the response tag. The flag TPM_CHIP_FLAG_TPM2 is set by + * this function if this is the case. * - * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on - * the reply tag. + * Return: + * 0 on success, + * -errno otherwise */ int tpm2_probe(struct tpm_chip *chip) { - struct tpm2_cmd cmd; + struct tpm_output_header *out; + struct tpm_buf buf; int rc; - cmd.header.in = tpm2_get_tpm_pt_header; - cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES); - cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); - cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - - rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, NULL); - if (rc < 0) + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); + if (rc) return rc; - - if (be16_to_cpu(cmd.header.out.tag) == TPM2_ST_NO_SESSIONS) - chip->flags |= TPM_CHIP_FLAG_TPM2; - + tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); + tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS); + tpm_buf_append_u32(&buf, 1); + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, NULL); + /* We ignore TPM return codes on purpose. */ + if (rc >= 0) { + out = (struct tpm_output_header *)buf.data; + if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS) + chip->flags |= TPM_CHIP_FLAG_TPM2; + } + tpm_buf_destroy(&buf); return 0; } EXPORT_SYMBOL_GPL(tpm2_probe); -- cgit v1.2.3 From 2ab3241161b3c340617063beea199e9966ee90c9 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 26 Mar 2018 15:14:05 +0300 Subject: tpm: migrate tpm2_get_tpm_pt() to use struct tpm_buf In order to make struct tpm_buf the first class object for constructing TPM commands, migrate tpm2_get_tpm_pt() to use it. Signed-off-by: Jarkko Sakkinen Reviewed-by: Nayna Jain Tested-by: Nayna Jain Reviewed-by: Jerry Snitselaar --- drivers/char/tpm/tpm2-cmd.c | 69 ++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index b82e2b141754..90e3b36cf0dc 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -27,20 +27,6 @@ enum tpm2_session_attributes { TPM2_SA_CONTINUE_SESSION = BIT(0), }; -struct tpm2_get_tpm_pt_in { - __be32 cap_id; - __be32 property_id; - __be32 property_cnt; -} __packed; - -struct tpm2_get_tpm_pt_out { - u8 more_data; - __be32 subcap_id; - __be32 property_cnt; - __be32 property_id; - __be32 value; -} __packed; - struct tpm2_get_random_in { __be16 size; } __packed; @@ -51,8 +37,6 @@ struct tpm2_get_random_out { } __packed; union tpm2_cmd_params { - 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; struct tpm2_get_random_out getrandom_out; }; @@ -379,19 +363,6 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) return total ? total : -EIO; } -#define TPM2_GET_TPM_PT_IN_SIZE \ - (sizeof(struct tpm_input_header) + \ - sizeof(struct tpm2_get_tpm_pt_in)) - -#define TPM2_GET_TPM_PT_OUT_BODY_SIZE \ - sizeof(struct tpm2_get_tpm_pt_out) - -static const struct tpm_input_header tpm2_get_tpm_pt_header = { - .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), - .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE), - .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY) -}; - /** * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command * @chip: TPM chip to use @@ -728,31 +699,45 @@ out: return rc; } +struct tpm2_get_cap_out { + u8 more_data; + __be32 subcap_id; + __be32 property_cnt; + __be32 property_id; + __be32 value; +} __packed; + /** * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property - * @chip: TPM chip to use. + * @chip: a &tpm_chip instance * @property_id: property ID. * @value: output variable. * @desc: passed to tpm_transmit_cmd() * - * Return: Same as with tpm_transmit_cmd. + * Return: + * 0 on success, + * -errno or a TPM return code otherwise */ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, const char *desc) { - struct tpm2_cmd cmd; + struct tpm2_get_cap_out *out; + struct tpm_buf buf; int rc; - cmd.header.in = tpm2_get_tpm_pt_header; - cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES); - cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); - cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - - rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), - TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc); - if (!rc) - *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value); - + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); + if (rc) + return rc; + tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); + tpm_buf_append_u32(&buf, property_id); + tpm_buf_append_u32(&buf, 1); + rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, NULL); + if (!rc) { + out = (struct tpm2_get_cap_out *) + &buf.data[TPM_HEADER_SIZE]; + *value = be32_to_cpu(out->value); + } + tpm_buf_destroy(&buf); return rc; } EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); -- cgit v1.2.3 From ce63c05b664e491b4cc79c713c68d8170bd0f581 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 26 Mar 2018 15:14:06 +0300 Subject: tpm: migrate tpm2_get_random() to use struct tpm_buf In order to make struct tpm_buf the first class object for constructing TPM commands, migrate tpm2_get_random() to use it. In addition, removed remaining references to struct tpm2_cmd. All of them use it to acquire the length of the response, which can be achieved by using tpm_buf_length(). Signed-off-by: Jarkko Sakkinen Tested-by: Nayna Jain --- drivers/char/tpm/tpm.h | 19 +++++---- drivers/char/tpm/tpm2-cmd.c | 102 ++++++++++++++++++-------------------------- 2 files changed, 51 insertions(+), 70 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 4426649e431c..9824cccb2c76 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -424,23 +424,24 @@ struct tpm_buf { u8 *data; }; -static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal) +static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal) { struct tpm_input_header *head; + head = (struct tpm_input_header *)buf->data; + head->tag = cpu_to_be16(tag); + head->length = cpu_to_be32(sizeof(*head)); + head->ordinal = cpu_to_be32(ordinal); +} +static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal) +{ buf->data_page = alloc_page(GFP_HIGHUSER); if (!buf->data_page) return -ENOMEM; buf->flags = 0; buf->data = kmap(buf->data_page); - - head = (struct tpm_input_header *) buf->data; - - head->tag = cpu_to_be16(tag); - head->length = cpu_to_be32(sizeof(*head)); - head->ordinal = cpu_to_be32(ordinal); - + tpm_buf_reset(buf, tag, ordinal); return 0; } @@ -569,7 +570,7 @@ static inline u32 tpm2_rc_value(u32 rc) int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, struct tpm2_digest *digests); -int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); +int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max); void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, unsigned int flags); int tpm2_seal_trusted(struct tpm_chip *chip, diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 90e3b36cf0dc..c31b490bd41d 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -27,25 +27,6 @@ enum tpm2_session_attributes { TPM2_SA_CONTINUE_SESSION = BIT(0), }; -struct tpm2_get_random_in { - __be16 size; -} __packed; - -struct tpm2_get_random_out { - __be16 size; - u8 buffer[TPM_MAX_RNG_DATA]; -} __packed; - -union tpm2_cmd_params { - struct tpm2_get_random_in getrandom_in; - struct tpm2_get_random_out getrandom_out; -}; - -struct tpm2_cmd { - tpm_cmd_header header; - union tpm2_cmd_params params; -} __packed; - struct tpm2_hash { unsigned int crypto_id; unsigned int tpm_id; @@ -300,67 +281,70 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, } -#define TPM2_GETRANDOM_IN_SIZE \ - (sizeof(struct tpm_input_header) + \ - sizeof(struct tpm2_get_random_in)) - -static const struct tpm_input_header tpm2_getrandom_header = { - .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), - .length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE), - .ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM) -}; +struct tpm2_get_random_out { + __be16 size; + u8 buffer[TPM_MAX_RNG_DATA]; +} __packed; /** * tpm2_get_random() - get random bytes from the TPM RNG * - * @chip: TPM chip to use - * @out: destination buffer for the random bytes - * @max: the max number of bytes to write to @out + * @chip: a &tpm_chip instance + * @dest: destination buffer + * @max: the max number of random bytes to pull * * Return: - * Size of the output buffer, or -EIO on error. + * size of the buffer on success, + * -errno otherwise */ -int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) +int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) { - struct tpm2_cmd cmd; - u32 recd, rlength; - u32 num_bytes; + struct tpm2_get_random_out *out; + struct tpm_buf buf; + u32 recd; + u32 num_bytes = max; int err; int total = 0; int retries = 5; - u8 *dest = out; - - num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer)); + u8 *dest_ptr = dest; - if (!out || !num_bytes || - max > sizeof(cmd.params.getrandom_out.buffer)) + if (!num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; - do { - cmd.header.in = tpm2_getrandom_header; - cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); + err = tpm_buf_init(&buf, 0, 0); + if (err) + return err; - err = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), + do { + tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM); + tpm_buf_append_u16(&buf, num_bytes); + err = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, offsetof(struct tpm2_get_random_out, buffer), 0, "attempting get random"); if (err) - break; + goto out; - recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size), - num_bytes); - rlength = be32_to_cpu(cmd.header.out.length); - if (rlength < offsetof(struct tpm2_get_random_out, buffer) + - recd) - return -EFAULT; - memcpy(dest, cmd.params.getrandom_out.buffer, recd); + out = (struct tpm2_get_random_out *) + &buf.data[TPM_HEADER_SIZE]; + recd = min_t(u32, be16_to_cpu(out->size), num_bytes); + if (tpm_buf_length(&buf) < + offsetof(struct tpm2_get_random_out, buffer) + recd) { + err = -EFAULT; + goto out; + } + memcpy(dest_ptr, out->buffer, recd); - dest += recd; + dest_ptr += recd; total += recd; num_bytes -= recd; } while (retries-- && total < max); + tpm_buf_destroy(&buf); return total ? total : -EIO; +out: + tpm_buf_destroy(&buf); + return err; } /** @@ -437,7 +421,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, { unsigned int blob_len; struct tpm_buf buf; - u32 hash, rlength; + u32 hash; int i; int rc; @@ -512,8 +496,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, rc = -E2BIG; goto out; } - rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)->header.out.length); - if (rlength < TPM_HEADER_SIZE + 4 + blob_len) { + if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) { rc = -EFAULT; goto out; } @@ -623,7 +606,6 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, u16 data_len; u8 *data; int rc; - u32 rlength; rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); if (rc) @@ -651,9 +633,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, goto out; } - rlength = be32_to_cpu(((struct tpm2_cmd *)&buf) - ->header.out.length); - if (rlength < TPM_HEADER_SIZE + 6 + data_len) { + if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) { rc = -EFAULT; goto out; } -- cgit v1.2.3 From 1a339b658d9dbe1471f67b78237cf8fa08bbbeb5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Jun 2018 09:09:07 +0200 Subject: tpm_tis_spi: Pass the SPI IRQ down to the driver An SPI TPM device managed directly on an embedded board using the SPI bus and some GPIO or similar line as IRQ handler will pass the IRQn from the TPM device associated with the SPI device. This is already handled by the SPI core, so make sure to pass this down to the core as well. (The TPM core habit of using -1 to signal no IRQ is dubious (as IRQ 0 is NO_IRQ) but I do not want to mess with that semantic in this patch.) Cc: Mark Brown Signed-off-by: Linus Walleij Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_spi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c index 424ff2fde1f2..9914f6973463 100644 --- a/drivers/char/tpm/tpm_tis_spi.c +++ b/drivers/char/tpm/tpm_tis_spi.c @@ -199,6 +199,7 @@ static const struct tpm_tis_phy_ops tpm_spi_phy_ops = { static int tpm_tis_spi_probe(struct spi_device *dev) { struct tpm_tis_spi_phy *phy; + int irq; phy = devm_kzalloc(&dev->dev, sizeof(struct tpm_tis_spi_phy), GFP_KERNEL); @@ -211,7 +212,13 @@ static int tpm_tis_spi_probe(struct spi_device *dev) if (!phy->iobuf) return -ENOMEM; - return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_spi_phy_ops, + /* If the SPI device has an IRQ then use that */ + if (dev->irq > 0) + irq = dev->irq; + else + irq = -1; + + return tpm_tis_core_init(&dev->dev, &phy->priv, irq, &tpm_spi_phy_ops, NULL); } -- cgit v1.2.3 From 79e2472f99ab457417aaad98bf83ab565fa32bd0 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 20 Jun 2018 07:17:54 +0200 Subject: tpm/tpm_i2c_infineon: switch to i2c_lock_bus(..., I2C_LOCK_SEGMENT) Locking the root adapter for __i2c_transfer will deadlock if the device sits behind a mux-locked I2C mux. Switch to the finer-grained i2c_lock_bus with the I2C_LOCK_SEGMENT flag. If the device does not sit behind a mux-locked mux, the two locking variants are equivalent. Signed-off-by: Peter Rosin Reviewed-by: Jarkko Sakkinen Tested-by: Alexander Steffen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_i2c_infineon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 6116cd05e228..9086edc9066b 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -117,7 +117,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) /* Lock the adapter for the duration of the whole sequence. */ if (!tpm_dev.client->adapter->algo->master_xfer) return -EOPNOTSUPP; - i2c_lock_adapter(tpm_dev.client->adapter); + i2c_lock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); if (tpm_dev.chip_type == SLB9645) { /* use a combined read for newer chips @@ -192,7 +192,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) } out: - i2c_unlock_adapter(tpm_dev.client->adapter); + i2c_unlock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); /* take care of 'guard time' */ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); @@ -224,7 +224,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, if (!tpm_dev.client->adapter->algo->master_xfer) return -EOPNOTSUPP; - i2c_lock_adapter(tpm_dev.client->adapter); + i2c_lock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); /* prepend the 'register address' to the buffer */ tpm_dev.buf[0] = addr; @@ -243,7 +243,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, usleep_range(sleep_low, sleep_hi); } - i2c_unlock_adapter(tpm_dev.client->adapter); + i2c_unlock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); /* take care of 'guard time' */ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); -- cgit v1.2.3 From 627448e85c766587f6fdde1ea3886d6615081c77 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 28 Jun 2018 18:13:33 +0300 Subject: tpm: separate cmd_ready/go_idle from runtime_pm Fix tpm ptt initialization error: tpm tpm0: A TPM error (378) occurred get tpm pcr allocation. We cannot use go_idle cmd_ready commands via runtime_pm handles as with the introduction of localities this is no longer an optional feature, while runtime pm can be not enabled. Though cmd_ready/go_idle provides a power saving, it's also a part of TPM2 protocol and should be called explicitly. This patch exposes cmd_read/go_idle via tpm class ops and removes runtime pm support as it is not used by any driver. When calling from nested context always use both flags: TPM_TRANSMIT_UNLOCKED and TPM_TRANSMIT_RAW. Both are needed to resolve tpm spaces and locality request recursive calls to tpm_transmit(). TPM_TRANSMIT_RAW should never be used standalone as it will fail on double locking. While TPM_TRANSMIT_UNLOCKED standalone should be called from non-recursive locked contexts. New wrappers are added tpm_cmd_ready() and tpm_go_idle() to streamline tpm_try_transmit code. tpm_crb no longer needs own power saving functions and can drop using tpm_pm_suspend/resume. This patch cannot be really separated from the locality fix. Fixes: 888d867df441 (tpm: cmd_ready command can be issued only after granting locality) Cc: stable@vger.kernel.org Fixes: 888d867df441 (tpm: cmd_ready command can be issued only after granting locality) Signed-off-by: Tomas Winkler Tested-by: Jarkko Sakkinen Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 51 ++++++++++++++++---- drivers/char/tpm/tpm.h | 12 ++++- drivers/char/tpm/tpm2-space.c | 16 ++++--- drivers/char/tpm/tpm_crb.c | 101 +++++++++++---------------------------- include/linux/tpm.h | 2 + 5 files changed, 90 insertions(+), 92 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index e32f6e85dc6d..31b86e027f9d 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include "tpm.h" @@ -369,10 +368,13 @@ err_len: return -EINVAL; } -static int tpm_request_locality(struct tpm_chip *chip) +static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags) { int rc; + if (flags & TPM_TRANSMIT_RAW) + return 0; + if (!chip->ops->request_locality) return 0; @@ -385,10 +387,13 @@ static int tpm_request_locality(struct tpm_chip *chip) return 0; } -static void tpm_relinquish_locality(struct tpm_chip *chip) +static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags) { int rc; + if (flags & TPM_TRANSMIT_RAW) + return; + if (!chip->ops->relinquish_locality) return; @@ -399,6 +404,28 @@ static void tpm_relinquish_locality(struct tpm_chip *chip) chip->locality = -1; } +static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags) +{ + if (flags & TPM_TRANSMIT_RAW) + return 0; + + if (!chip->ops->cmd_ready) + return 0; + + return chip->ops->cmd_ready(chip); +} + +static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags) +{ + if (flags & TPM_TRANSMIT_RAW) + return 0; + + if (!chip->ops->go_idle) + return 0; + + return chip->ops->go_idle(chip); +} + static ssize_t tpm_try_transmit(struct tpm_chip *chip, struct tpm_space *space, u8 *buf, size_t bufsiz, @@ -449,14 +476,15 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; - if (!(flags & TPM_TRANSMIT_RAW) && need_locality) { - rc = tpm_request_locality(chip); + if (need_locality) { + rc = tpm_request_locality(chip, flags); if (rc < 0) goto out_no_locality; } - if (chip->dev.parent) - pm_runtime_get_sync(chip->dev.parent); + rc = tpm_cmd_ready(chip, flags); + if (rc) + goto out; rc = tpm2_prepare_space(chip, space, ordinal, buf); if (rc) @@ -516,13 +544,16 @@ out_recv: } rc = tpm2_commit_space(chip, space, ordinal, buf, &len); + if (rc) + dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc); out: - if (chip->dev.parent) - pm_runtime_put_sync(chip->dev.parent); + rc = tpm_go_idle(chip, flags); + if (rc) + goto out; if (need_locality) - tpm_relinquish_locality(chip); + tpm_relinquish_locality(chip, flags); out_no_locality: if (chip->ops->clk_enable != NULL) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 9824cccb2c76..17833ef63f6c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -512,9 +512,17 @@ extern const struct file_operations tpm_fops; extern const struct file_operations tpmrm_fops; extern struct idr dev_nums_idr; +/** + * enum tpm_transmit_flags + * + * @TPM_TRANSMIT_UNLOCKED: used to lock sequence of tpm_transmit calls. + * @TPM_TRANSMIT_RAW: prevent recursive calls into setup steps + * (go idle, locality,..). Always use with UNLOCKED + * as it will fail on double locking. + */ enum tpm_transmit_flags { - TPM_TRANSMIT_UNLOCKED = BIT(0), - TPM_TRANSMIT_RAW = BIT(1), + TPM_TRANSMIT_UNLOCKED = BIT(0), + TPM_TRANSMIT_RAW = BIT(1), }; ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index 6122d3276f72..11c85ed8c113 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -39,7 +39,8 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { if (space->session_tbl[i]) tpm2_flush_context_cmd(chip, space->session_tbl[i], - TPM_TRANSMIT_UNLOCKED); + TPM_TRANSMIT_UNLOCKED | + TPM_TRANSMIT_RAW); } } @@ -84,7 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, tpm_buf_append(&tbuf, &buf[*offset], body_size); rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, - TPM_TRANSMIT_UNLOCKED, NULL); + TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -133,7 +134,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, tpm_buf_append_u32(&tbuf, handle); rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0, - TPM_TRANSMIT_UNLOCKED, NULL); + TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -170,7 +171,8 @@ static void tpm2_flush_space(struct tpm_chip *chip) for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) if (space->context_tbl[i] && ~space->context_tbl[i]) tpm2_flush_context_cmd(chip, space->context_tbl[i], - TPM_TRANSMIT_UNLOCKED); + TPM_TRANSMIT_UNLOCKED | + TPM_TRANSMIT_RAW); tpm2_flush_sessions(chip, space); } @@ -377,7 +379,8 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, return 0; out_no_slots: - tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_UNLOCKED); + tpm2_flush_context_cmd(chip, phandle, + TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW); dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, phandle); return -ENOMEM; @@ -465,7 +468,8 @@ static int tpm2_save_space(struct tpm_chip *chip) return rc; tpm2_flush_context_cmd(chip, space->context_tbl[i], - TPM_TRANSMIT_UNLOCKED); + TPM_TRANSMIT_UNLOCKED | + TPM_TRANSMIT_RAW); space->context_tbl[i] = ~0; } diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 34fbc6cb097b..36952ef98f90 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -132,7 +132,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, } /** - * crb_go_idle - request tpm crb device to go the idle state + * __crb_go_idle - request tpm crb device to go the idle state * * @dev: crb device * @priv: crb private data @@ -147,7 +147,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, * * Return: 0 always */ -static int crb_go_idle(struct device *dev, struct crb_priv *priv) +static int __crb_go_idle(struct device *dev, struct crb_priv *priv) { if ((priv->sm == ACPI_TPM2_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || @@ -163,11 +163,20 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv) dev_warn(dev, "goIdle timed out\n"); return -ETIME; } + return 0; } +static int crb_go_idle(struct tpm_chip *chip) +{ + struct device *dev = &chip->dev; + struct crb_priv *priv = dev_get_drvdata(dev); + + return __crb_go_idle(dev, priv); +} + /** - * crb_cmd_ready - request tpm crb device to enter ready state + * __crb_cmd_ready - request tpm crb device to enter ready state * * @dev: crb device * @priv: crb private data @@ -181,7 +190,7 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv) * * Return: 0 on success -ETIME on timeout; */ -static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) +static int __crb_cmd_ready(struct device *dev, struct crb_priv *priv) { if ((priv->sm == ACPI_TPM2_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || @@ -200,6 +209,14 @@ static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) return 0; } +static int crb_cmd_ready(struct tpm_chip *chip) +{ + struct device *dev = &chip->dev; + struct crb_priv *priv = dev_get_drvdata(dev); + + return __crb_cmd_ready(dev, priv); +} + static int __crb_request_locality(struct device *dev, struct crb_priv *priv, int loc) { @@ -401,6 +418,8 @@ static const struct tpm_class_ops tpm_crb = { .send = crb_send, .cancel = crb_cancel, .req_canceled = crb_req_canceled, + .go_idle = crb_go_idle, + .cmd_ready = crb_cmd_ready, .request_locality = crb_request_locality, .relinquish_locality = crb_relinquish_locality, .req_complete_mask = CRB_DRV_STS_COMPLETE, @@ -520,7 +539,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, * PTT HW bug w/a: wake up the device to access * possibly not retained registers. */ - ret = crb_cmd_ready(dev, priv); + ret = __crb_cmd_ready(dev, priv); if (ret) goto out_relinquish_locality; @@ -565,7 +584,7 @@ out: if (!ret) priv->cmd_size = cmd_size; - crb_go_idle(dev, priv); + __crb_go_idle(dev, priv); out_relinquish_locality: @@ -628,32 +647,7 @@ static int crb_acpi_add(struct acpi_device *device) chip->acpi_dev_handle = device->handle; chip->flags = TPM_CHIP_FLAG_TPM2; - rc = __crb_request_locality(dev, priv, 0); - if (rc) - return rc; - - rc = crb_cmd_ready(dev, priv); - if (rc) - goto out; - - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - rc = tpm_chip_register(chip); - if (rc) { - crb_go_idle(dev, priv); - pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); - goto out; - } - - pm_runtime_put_sync(dev); - -out: - __crb_relinquish_locality(dev, priv, 0); - - return rc; + return tpm_chip_register(chip); } static int crb_acpi_remove(struct acpi_device *device) @@ -663,52 +657,11 @@ static int crb_acpi_remove(struct acpi_device *device) tpm_chip_unregister(chip); - pm_runtime_disable(dev); - return 0; } -static int __maybe_unused crb_pm_runtime_suspend(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct crb_priv *priv = dev_get_drvdata(&chip->dev); - - return crb_go_idle(dev, priv); -} - -static int __maybe_unused crb_pm_runtime_resume(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct crb_priv *priv = dev_get_drvdata(&chip->dev); - - return crb_cmd_ready(dev, priv); -} - -static int __maybe_unused crb_pm_suspend(struct device *dev) -{ - int ret; - - ret = tpm_pm_suspend(dev); - if (ret) - return ret; - - return crb_pm_runtime_suspend(dev); -} - -static int __maybe_unused crb_pm_resume(struct device *dev) -{ - int ret; - - ret = crb_pm_runtime_resume(dev); - if (ret) - return ret; - - return tpm_pm_resume(dev); -} - static const struct dev_pm_ops crb_pm = { - SET_SYSTEM_SLEEP_PM_OPS(crb_pm_suspend, crb_pm_resume) - SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume) }; static const struct acpi_device_id crb_device_ids[] = { diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 06639fb6ab85..8eb5e5ebe136 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -43,6 +43,8 @@ struct tpm_class_ops { u8 (*status) (struct tpm_chip *chip); bool (*update_timeouts)(struct tpm_chip *chip, unsigned long *timeout_cap); + int (*go_idle)(struct tpm_chip *chip); + int (*cmd_ready)(struct tpm_chip *chip); int (*request_locality)(struct tpm_chip *chip, int loc); int (*relinquish_locality)(struct tpm_chip *chip, int loc); void (*clk_enable)(struct tpm_chip *chip, bool value); -- cgit v1.2.3 From 36a11029b07ee30bdc4553274d0efea645ed9d91 Mon Sep 17 00:00:00 2001 From: Ricardo Schwarzmeier Date: Tue, 26 Jun 2018 17:31:45 +0200 Subject: tpm: Return the actual size when receiving an unsupported command The userpace expects to read the number of bytes stated in the header. Returning the size of the buffer instead would be unexpected. Cc: stable@vger.kernel.org Fixes: 095531f891e6 ("tpm: return a TPM_RC_COMMAND_CODE response if command is not implemented") Signed-off-by: Ricardo Schwarzmeier Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 31b86e027f9d..3a3a7a548a85 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -450,7 +450,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, 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; + return sizeof(*header); } if (bufsiz > TPM_BUFSIZE) -- cgit v1.2.3 From 7a64c5597aa40403e9f8319c0664228a5580c121 Mon Sep 17 00:00:00 2001 From: Louis Collard Date: Fri, 29 Jun 2018 16:13:55 +0800 Subject: tpm: Allow tpm_tis drivers to set hwrng quality. Adds plumbing required for drivers based on tpm_tis to set hwrng quality. Signed-off-by: Louis Collard Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_core.c | 2 ++ drivers/char/tpm/tpm_tis_core.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 8b46aaa9e049..d2345d9fd7b5 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -875,6 +875,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, chip->acpi_dev_handle = acpi_dev_handle; #endif + chip->hwrng.quality = priv->rng_quality; + /* Maximum timeouts */ chip->timeout_a = msecs_to_jiffies(TIS_TIMEOUT_A_MAX); chip->timeout_b = msecs_to_jiffies(TIS_TIMEOUT_B_MAX); diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index f6e1dbe212a7..f48125f1e6e0 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -99,6 +99,7 @@ struct tpm_tis_data { wait_queue_head_t int_queue; wait_queue_head_t read_queue; const struct tpm_tis_phy_ops *phy_ops; + unsigned short rng_quality; }; struct tpm_tis_phy_ops { -- cgit v1.2.3 From fc1d52b745bae6108102096d85e743ac33b446f2 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 26 Jun 2018 07:06:15 -0400 Subject: tpm: rename tpm_chip_find_get() to tpm_find_get_ops() Rename tpm_chip_find_get() to tpm_find_get_ops() to more closely match the tpm_put_ops() counter part. Signed-off-by: Stefan Berger Tested-by: Jarkko Sakkinen Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 9 ++++++--- drivers/char/tpm/tpm-interface.c | 14 +++++++------- drivers/char/tpm/tpm.h | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 0a62c19937b6..242b716aed5e 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -81,18 +81,21 @@ void tpm_put_ops(struct tpm_chip *chip) EXPORT_SYMBOL_GPL(tpm_put_ops); /** - * tpm_chip_find_get() - find and reserve a TPM 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_chip_put_ops() after use. + * 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_chip_find_get(struct tpm_chip *chip) +struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip) { struct tpm_chip *res = NULL; int chip_num = 0; diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3a3a7a548a85..ad761e629a0f 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -961,7 +961,7 @@ int tpm_is_tpm2(struct tpm_chip *chip) { int rc; - chip = tpm_chip_find_get(chip); + chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; @@ -985,7 +985,7 @@ int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { int rc; - chip = tpm_chip_find_get(chip); + chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) @@ -1044,7 +1044,7 @@ int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) u32 count = 0; int i; - chip = tpm_chip_find_get(chip); + chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; @@ -1173,7 +1173,7 @@ int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { int rc; - chip = tpm_chip_find_get(chip); + chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; @@ -1293,7 +1293,7 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; - chip = tpm_chip_find_get(chip); + chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; @@ -1355,7 +1355,7 @@ int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, { int rc; - chip = tpm_chip_find_get(chip); + chip = tpm_find_get_ops(chip); if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; @@ -1383,7 +1383,7 @@ int tpm_unseal_trusted(struct tpm_chip *chip, { int rc; - chip = tpm_chip_find_get(chip); + chip = tpm_find_get_ops(chip); if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 17833ef63f6c..ba01488cd029 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -547,7 +547,7 @@ static inline void tpm_msleep(unsigned int delay_msec) delay_msec * 1000); }; -struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip); +struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip); __must_check int tpm_try_get_ops(struct tpm_chip *chip); void tpm_put_ops(struct tpm_chip *chip); -- cgit v1.2.3 From aaae81536351f831fe6719e5b4e6afbadc5e5f85 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 26 Jun 2018 15:09:30 -0400 Subject: tpm: Implement tpm_default_chip() to find a TPM chip Implement tpm_default_chip() to find the first TPM chip and return it to the caller while increasing the reference count on its device. This function can be used by other subsystems, such as IMA, to find the system's default TPM chip and use it for all subsequent TPM operations. Signed-off-by: Stefan Berger Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 27 +++++++++++++++++++++++++++ include/linux/tpm.h | 5 +++++ 2 files changed, 32 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 242b716aed5e..f551061262c9 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -80,6 +80,33 @@ void tpm_put_ops(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_put_ops); +/** + * tpm_default_chip() - find a TPM chip and get a reference to it + */ +struct tpm_chip *tpm_default_chip(void) +{ + struct tpm_chip *chip, *res = NULL; + int chip_num = 0; + int chip_prev; + + mutex_lock(&idr_lock); + + do { + chip_prev = chip_num; + chip = idr_get_next(&dev_nums_idr, &chip_num); + if (chip) { + get_device(&chip->dev); + res = chip; + break; + } + } while (chip_prev != chip_num); + + mutex_unlock(&idr_lock); + + return res; +} +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 diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 8eb5e5ebe136..4609b94142d4 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -63,6 +63,7 @@ extern int tpm_seal_trusted(struct tpm_chip *chip, extern int tpm_unseal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options); +extern struct tpm_chip *tpm_default_chip(void); #else static inline int tpm_is_tpm2(struct tpm_chip *chip) { @@ -98,5 +99,9 @@ static inline int tpm_unseal_trusted(struct tpm_chip *chip, { return -ENODEV; } +static inline struct tpm_chip *tpm_default_chip(void) +{ + return NULL; +} #endif #endif -- cgit v1.2.3 From eccc9bb844838b6b7a9691b31747416c4c34a83f Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 26 Jun 2018 15:09:31 -0400 Subject: tpm: Convert tpm_find_get_ops() to use tpm_default_chip() Convert tpm_find_get_ops() to use tpm_default_chip() in case no chip is passed in. Signed-off-by: Stefan Berger Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index f551061262c9..46caadca916a 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -124,29 +124,23 @@ EXPORT_SYMBOL_GPL(tpm_default_chip); */ struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip) { - struct tpm_chip *res = NULL; - int chip_num = 0; - int chip_prev; - - mutex_lock(&idr_lock); + int rc; - if (!chip) { - do { - chip_prev = chip_num; - chip = idr_get_next(&dev_nums_idr, &chip_num); - if (chip && !tpm_try_get_ops(chip)) { - res = chip; - break; - } - } while (chip_prev != chip_num); - } else { + if (chip) { if (!tpm_try_get_ops(chip)) - res = chip; + return chip; + return NULL; } - mutex_unlock(&idr_lock); - - return res; + 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; } /** -- cgit v1.2.3 From 58bac8cc3010ccb845572a3512fc16c9aaa5e50e Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 29 Jun 2018 15:24:50 +0300 Subject: tpm: replace TPM_TRANSMIT_RAW with TPM_TRANSMIT_NESTED As TPM_TRANSMIT_RAW always requires also not to take locks for obvious reasons (deadlock), this commit renames the flag as TPM_TRANSMIT_NESTED and prevents taking tpm_mutex when the flag is given to tpm_transmit(). Suggested-by: Tomas Winkler Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 13 ++++++------- drivers/char/tpm/tpm.h | 14 +++++++------- drivers/char/tpm/tpm2-space.c | 16 ++++++---------- drivers/char/tpm/tpm_vtpm_proxy.c | 2 +- 4 files changed, 20 insertions(+), 25 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index ad761e629a0f..1a803b0cf980 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -372,7 +372,7 @@ static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags) { int rc; - if (flags & TPM_TRANSMIT_RAW) + if (flags & TPM_TRANSMIT_NESTED) return 0; if (!chip->ops->request_locality) @@ -391,7 +391,7 @@ static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags) { int rc; - if (flags & TPM_TRANSMIT_RAW) + if (flags & TPM_TRANSMIT_NESTED) return; if (!chip->ops->relinquish_locality) @@ -406,7 +406,7 @@ static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags) static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags) { - if (flags & TPM_TRANSMIT_RAW) + if (flags & TPM_TRANSMIT_NESTED) return 0; if (!chip->ops->cmd_ready) @@ -417,7 +417,7 @@ static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags) static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags) { - if (flags & TPM_TRANSMIT_RAW) + if (flags & TPM_TRANSMIT_NESTED) return 0; if (!chip->ops->go_idle) @@ -466,10 +466,9 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, return -E2BIG; } - if (!(flags & TPM_TRANSMIT_UNLOCKED)) + if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED)) mutex_lock(&chip->tpm_mutex); - if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, true); @@ -559,7 +558,7 @@ out_no_locality: if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, false); - if (!(flags & TPM_TRANSMIT_UNLOCKED)) + if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED)) mutex_unlock(&chip->tpm_mutex); return rc ? rc : len; } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index ba01488cd029..f3501d05264f 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -513,16 +513,16 @@ extern const struct file_operations tpmrm_fops; extern struct idr dev_nums_idr; /** - * enum tpm_transmit_flags + * enum tpm_transmit_flags - flags for tpm_transmit() * - * @TPM_TRANSMIT_UNLOCKED: used to lock sequence of tpm_transmit calls. - * @TPM_TRANSMIT_RAW: prevent recursive calls into setup steps - * (go idle, locality,..). Always use with UNLOCKED - * as it will fail on double locking. + * @TPM_TRANSMIT_UNLOCKED: do not lock the chip + * @TPM_TRANSMIT_NESTED: discard setup steps (power management, + * locality) including locking (i.e. implicit + * UNLOCKED) */ enum tpm_transmit_flags { - TPM_TRANSMIT_UNLOCKED = BIT(0), - TPM_TRANSMIT_RAW = BIT(1), + TPM_TRANSMIT_UNLOCKED = BIT(0), + TPM_TRANSMIT_NESTED = BIT(1), }; ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index 11c85ed8c113..d2e101b32482 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -39,8 +39,7 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { if (space->session_tbl[i]) tpm2_flush_context_cmd(chip, space->session_tbl[i], - TPM_TRANSMIT_UNLOCKED | - TPM_TRANSMIT_RAW); + TPM_TRANSMIT_NESTED); } } @@ -85,7 +84,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, tpm_buf_append(&tbuf, &buf[*offset], body_size); rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, - TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL); + TPM_TRANSMIT_NESTED, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -134,7 +133,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, tpm_buf_append_u32(&tbuf, handle); rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0, - TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL); + TPM_TRANSMIT_NESTED, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -171,8 +170,7 @@ static void tpm2_flush_space(struct tpm_chip *chip) for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) if (space->context_tbl[i] && ~space->context_tbl[i]) tpm2_flush_context_cmd(chip, space->context_tbl[i], - TPM_TRANSMIT_UNLOCKED | - TPM_TRANSMIT_RAW); + TPM_TRANSMIT_NESTED); tpm2_flush_sessions(chip, space); } @@ -379,8 +377,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, return 0; out_no_slots: - tpm2_flush_context_cmd(chip, phandle, - TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW); + tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_NESTED); dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, phandle); return -ENOMEM; @@ -468,8 +465,7 @@ static int tpm2_save_space(struct tpm_chip *chip) return rc; tpm2_flush_context_cmd(chip, space->context_tbl[i], - TPM_TRANSMIT_UNLOCKED | - TPM_TRANSMIT_RAW); + TPM_TRANSMIT_NESTED); space->context_tbl[i] = ~0; } diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index e4f79f920450..87a0ce47f201 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -418,7 +418,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality) proxy_dev->state |= STATE_DRIVER_COMMAND; rc = tpm_transmit_cmd(chip, NULL, buf.data, tpm_buf_length(&buf), 0, - TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, + TPM_TRANSMIT_NESTED, "attempting to set locality"); proxy_dev->state &= ~STATE_DRIVER_COMMAND; -- cgit v1.2.3