diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-11 01:37:29 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-11 01:37:29 +0100 |
commit | 5af7f115886f7ec193171e2e49b8000ddd1e7147 (patch) | |
tree | 117b9e99650b0772f683e6b8f734e2c94f6a6c3b /drivers/char | |
parent | Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/gi... (diff) | |
parent | Merge tag 'tpmdd-next-20190213' of git://git.infradead.org/users/jjs/linux-tp... (diff) | |
download | linux-5af7f115886f7ec193171e2e49b8000ddd1e7147.tar.xz linux-5af7f115886f7ec193171e2e49b8000ddd1e7147.zip |
Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull tpm updates from James Morris:
- Clean up the transmission flow
Cleaned up the whole transmission flow. Locking of the chip is now
done in the level of tpm_try_get_ops() and tpm_put_ops() instead
taking the chip lock inside tpm_transmit(). The nested calls inside
tpm_transmit(), used with the resource manager, have been refactored
out.
Should make easier to perform more complex transactions with the TPM
without making the subsystem a bigger mess (e.g. encrypted channel
patches by James Bottomley).
- PPI 1.3 support
TPM PPI 1.3 introduces an additional optional command parameter that
may be needed for some commands. Display the parameter if the command
requires such a parameter. Only command 23 (SetPCRBanks) needs one.
The PPI request file will show output like this then:
# echo "23 16" > request
# cat request
23 16
# echo "5" > request
# cat request
5
- Extend all PCR banks in IMA
Instead of static PCR banks array, the array of available PCR banks
is now allocated dynamically. The digests sizes are determined
dynamically using a probe PCR read without relying crypto's static
list of hash algorithms.
This should finally make sealing of measurements in IMA safe and
secure.
- TPM 2.0 selftests
Added a test suite to tools/testing/selftests/tpm2 previously outside
of the kernel tree: https://github.com/jsakkine-intel/tpm2-scripts
* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (37 commits)
tpm/ppi: Enable submission of optional command parameter for PPI 1.3
tpm/ppi: Possibly show command parameter if TPM PPI 1.3 is used
tpm/ppi: Display up to 101 operations as define for version 1.3
tpm/ppi: rename TPM_PPI_REVISION_ID to TPM_PPI_REVISION_ID_1
tpm/ppi: pass function revision ID to tpm_eval_dsm()
tpm: pass an array of tpm_extend_digest structures to tpm_pcr_extend()
KEYS: trusted: explicitly use tpm_chip structure from tpm_default_chip()
tpm: move tpm_chip definition to include/linux/tpm.h
tpm: retrieve digest size of unknown algorithms with PCR read
tpm: rename and export tpm2_digest and tpm2_algorithms
tpm: dynamically allocate the allocated_banks array
tpm: remove @flags from tpm_transmit()
tpm: take TPM chip power gating out of tpm_transmit()
tpm: introduce tpm_chip_start() and tpm_chip_stop()
tpm: remove TPM_TRANSMIT_UNLOCKED flag
tpm: use tpm_try_get_ops() in tpm-sysfs.c.
tpm: remove @space from tpm_transmit()
tpm: move TPM space code out of tpm_transmit()
tpm: move tpm_validate_commmand() to tpm2-space.c
tpm: clean up tpm_try_transmit() error handling flow
...
Diffstat (limited to 'drivers/char')
26 files changed, 721 insertions, 700 deletions
diff --git a/drivers/char/tpm/eventlog/tpm1.c b/drivers/char/tpm/eventlog/tpm1.c index 58c84784ba25..bfdff9271be0 100644 --- a/drivers/char/tpm/eventlog/tpm1.c +++ b/drivers/char/tpm/eventlog/tpm1.c @@ -74,7 +74,7 @@ static const char* tcpa_pc_event_id_strings[] = { /* returns pointer to start of pos. entry of tcg log */ static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos) { - loff_t i; + loff_t i = 0; struct tpm_chip *chip = m->private; struct tpm_bios_log *log = &chip->log; void *addr = log->bios_event_log; @@ -83,38 +83,29 @@ static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos) u32 converted_event_size; u32 converted_event_type; - /* read over *pos measurements */ - for (i = 0; i < *pos; i++) { + do { event = addr; + /* check if current entry is valid */ + if (addr + sizeof(struct tcpa_event) > limit) + return NULL; + converted_event_size = do_endian_conversion(event->event_size); converted_event_type = do_endian_conversion(event->event_type); - if ((addr + sizeof(struct tcpa_event)) < limit) { - if ((converted_event_type == 0) && - (converted_event_size == 0)) - return NULL; - addr += (sizeof(struct tcpa_event) + - converted_event_size); - } - } - - /* now check if current entry is valid */ - if ((addr + sizeof(struct tcpa_event)) >= limit) - return NULL; - - event = addr; + if (((converted_event_type == 0) && (converted_event_size == 0)) + || ((addr + sizeof(struct tcpa_event) + converted_event_size) + > limit)) + return NULL; - converted_event_size = do_endian_conversion(event->event_size); - converted_event_type = do_endian_conversion(event->event_type); + if (i++ == *pos) + break; - if (((converted_event_type == 0) && (converted_event_size == 0)) - || ((addr + sizeof(struct tcpa_event) + converted_event_size) - >= limit)) - return NULL; + addr += (sizeof(struct tcpa_event) + converted_event_size); + } while (1); return addr; } @@ -134,7 +125,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, v += sizeof(struct tcpa_event) + converted_event_size; /* now check if current entry is valid */ - if ((v + sizeof(struct tcpa_event)) >= limit) + if ((v + sizeof(struct tcpa_event)) > limit) return NULL; event = v; @@ -143,7 +134,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, converted_event_type = do_endian_conversion(event->event_type); if (((converted_event_type == 0) && (converted_event_size == 0)) || - ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit)) + ((v + sizeof(struct tcpa_event) + converted_event_size) > limit)) return NULL; (*pos)++; diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c index 1b8fa9de2cac..d8b77133a83a 100644 --- a/drivers/char/tpm/eventlog/tpm2.c +++ b/drivers/char/tpm/eventlog/tpm2.c @@ -37,10 +37,10 @@ * * Returns size of the event. If it is an invalid event, returns 0. */ -static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, +static int calc_tpm2_event_size(struct tcg_pcr_event2_head *event, struct tcg_pcr_event *event_header) { - struct tcg_efi_specid_event *efispecid; + struct tcg_efi_specid_event_head *efispecid; struct tcg_event_field *event_field; void *marker; void *marker_start; @@ -55,7 +55,7 @@ static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) + sizeof(event->count); - efispecid = (struct tcg_efi_specid_event *)event_header->event; + efispecid = (struct tcg_efi_specid_event_head *)event_header->event; /* Check if event is malformed. */ if (event->count > efispecid->num_algs) @@ -95,7 +95,7 @@ static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) void *addr = log->bios_event_log; void *limit = log->bios_event_log_end; struct tcg_pcr_event *event_header; - struct tcg_pcr_event2 *event; + struct tcg_pcr_event2_head *event; size_t size; int i; @@ -136,7 +136,7 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, loff_t *pos) { struct tcg_pcr_event *event_header; - struct tcg_pcr_event2 *event; + struct tcg_pcr_event2_head *event; struct tpm_chip *chip = m->private; struct tpm_bios_log *log = &chip->log; void *limit = log->bios_event_log_end; @@ -180,7 +180,7 @@ static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) struct tpm_chip *chip = m->private; struct tpm_bios_log *log = &chip->log; struct tcg_pcr_event *event_header = log->bios_event_log; - struct tcg_pcr_event2 *event = v; + struct tcg_pcr_event2_head *event = v; void *temp_ptr; size_t size; diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c index be5d1abd3e8e..8390c5b54c3b 100644 --- a/drivers/char/tpm/st33zp24/i2c.c +++ b/drivers/char/tpm/st33zp24/i2c.c @@ -33,7 +33,7 @@ struct st33zp24_i2c_phy { struct i2c_client *client; - u8 buf[TPM_BUFSIZE + 1]; + u8 buf[ST33ZP24_BUFSIZE + 1]; int io_lpcpd; }; diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c index d7909ab287a8..ff019a1e3c68 100644 --- a/drivers/char/tpm/st33zp24/spi.c +++ b/drivers/char/tpm/st33zp24/spi.c @@ -63,7 +63,7 @@ * some latency byte before the answer is available (max 15). * We have 2048 + 1024 + 15. */ -#define ST33ZP24_SPI_BUFFER_SIZE (TPM_BUFSIZE + (TPM_BUFSIZE / 2) +\ +#define ST33ZP24_SPI_BUFFER_SIZE (ST33ZP24_BUFSIZE + (ST33ZP24_BUFSIZE / 2) +\ MAX_SPI_LATENCY) diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 64dc560859f2..13dc614b7ebc 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -436,7 +436,7 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, goto out_err; } - return len; + return 0; out_err: st33zp24_cancel(chip); release_locality(chip); diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h index 6f4a4198af6a..20da0a84988d 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.h +++ b/drivers/char/tpm/st33zp24/st33zp24.h @@ -18,8 +18,8 @@ #ifndef __LOCAL_ST33ZP24_H__ #define __LOCAL_ST33ZP24_H__ -#define TPM_WRITE_DIRECTION 0x80 -#define TPM_BUFSIZE 2048 +#define TPM_WRITE_DIRECTION 0x80 +#define ST33ZP24_BUFSIZE 2048 struct st33zp24_dev { struct tpm_chip *chip; diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 32db84683c40..8804c9e916fd 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -37,6 +37,103 @@ struct class *tpm_class; struct class *tpmrm_class; dev_t tpm_devt; +static int tpm_request_locality(struct tpm_chip *chip) +{ + int rc; + + if (!chip->ops->request_locality) + return 0; + + rc = chip->ops->request_locality(chip, 0); + if (rc < 0) + return rc; + + chip->locality = rc; + return 0; +} + +static void tpm_relinquish_locality(struct tpm_chip *chip) +{ + int rc; + + if (!chip->ops->relinquish_locality) + return; + + rc = chip->ops->relinquish_locality(chip, chip->locality); + if (rc) + dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); + + chip->locality = -1; +} + +static int tpm_cmd_ready(struct tpm_chip *chip) +{ + if (!chip->ops->cmd_ready) + return 0; + + return chip->ops->cmd_ready(chip); +} + +static int tpm_go_idle(struct tpm_chip *chip) +{ + if (!chip->ops->go_idle) + return 0; + + return chip->ops->go_idle(chip); +} + +/** + * tpm_chip_start() - power on the TPM + * @chip: a TPM chip to use + * + * Return: + * * The response length - OK + * * -errno - A system error + */ +int tpm_chip_start(struct tpm_chip *chip) +{ + int ret; + + if (chip->ops->clk_enable) + chip->ops->clk_enable(chip, true); + + if (chip->locality == -1) { + ret = tpm_request_locality(chip); + if (ret) { + chip->ops->clk_enable(chip, false); + return ret; + } + } + + ret = tpm_cmd_ready(chip); + if (ret) { + tpm_relinquish_locality(chip); + if (chip->ops->clk_enable) + chip->ops->clk_enable(chip, false); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(tpm_chip_start); + +/** + * tpm_chip_stop() - power off the TPM + * @chip: a TPM chip to use + * + * Return: + * * The response length - OK + * * -errno - A system error + */ +void tpm_chip_stop(struct tpm_chip *chip) +{ + tpm_go_idle(chip); + tpm_relinquish_locality(chip); + if (chip->ops->clk_enable) + chip->ops->clk_enable(chip, false); +} +EXPORT_SYMBOL_GPL(tpm_chip_stop); + /** * tpm_try_get_ops() - Get a ref to the tpm_chip * @chip: Chip to ref @@ -56,10 +153,17 @@ int tpm_try_get_ops(struct tpm_chip *chip) down_read(&chip->ops_sem); if (!chip->ops) + goto out_ops; + + mutex_lock(&chip->tpm_mutex); + rc = tpm_chip_start(chip); + if (rc) goto out_lock; return 0; out_lock: + mutex_unlock(&chip->tpm_mutex); +out_ops: up_read(&chip->ops_sem); put_device(&chip->dev); return rc; @@ -75,6 +179,8 @@ EXPORT_SYMBOL_GPL(tpm_try_get_ops); */ void tpm_put_ops(struct tpm_chip *chip) { + tpm_chip_stop(chip); + mutex_unlock(&chip->tpm_mutex); up_read(&chip->ops_sem); put_device(&chip->dev); } @@ -160,6 +266,7 @@ static void tpm_dev_release(struct device *dev) kfree(chip->log.bios_event_log); kfree(chip->work_space.context_buf); kfree(chip->work_space.session_buf); + kfree(chip->allocated_banks); kfree(chip); } @@ -189,7 +296,10 @@ static int tpm_class_shutdown(struct device *dev) if (chip->flags & TPM_CHIP_FLAG_TPM2) { down_write(&chip->ops_sem); - tpm2_shutdown(chip, TPM2_SU_CLEAR); + if (!tpm_chip_start(chip)) { + tpm2_shutdown(chip, TPM2_SU_CLEAR); + tpm_chip_stop(chip); + } chip->ops = NULL; up_write(&chip->ops_sem); } @@ -368,8 +478,12 @@ static void tpm_del_char_device(struct tpm_chip *chip) /* Make the driver uncallable. */ down_write(&chip->ops_sem); - if (chip->flags & TPM_CHIP_FLAG_TPM2) - tpm2_shutdown(chip, TPM2_SU_CLEAR); + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + if (!tpm_chip_start(chip)) { + tpm2_shutdown(chip, TPM2_SU_CLEAR); + tpm_chip_stop(chip); + } + } chip->ops = NULL; up_write(&chip->ops_sem); } @@ -451,7 +565,11 @@ int tpm_chip_register(struct tpm_chip *chip) { int rc; + rc = tpm_chip_start(chip); + if (rc) + return rc; rc = tpm_auto_startup(chip); + tpm_chip_stop(chip); if (rc) return rc; diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index 5eecad233ea1..8856cce5a23b 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -27,7 +27,38 @@ static struct workqueue_struct *tpm_dev_wq; static DEFINE_MUTEX(tpm_dev_wq_lock); -static void tpm_async_work(struct work_struct *work) +static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space, + u8 *buf, size_t bufsiz) +{ + struct tpm_header *header = (void *)buf; + ssize_t ret, len; + + ret = tpm2_prepare_space(chip, space, buf, bufsiz); + /* If the command is not implemented by the TPM, synthesize a + * response with a TPM2_RC_COMMAND_CODE return for user-space. + */ + if (ret == -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); + ret = sizeof(*header); + } + if (ret) + goto out_rc; + + len = tpm_transmit(chip, buf, bufsiz); + if (len < 0) + ret = len; + + if (!ret) + ret = tpm2_commit_space(chip, space, buf, &len); + +out_rc: + return ret ? ret : len; +} + +static void tpm_dev_async_work(struct work_struct *work) { struct file_priv *priv = container_of(work, struct file_priv, async_work); @@ -35,9 +66,8 @@ static void tpm_async_work(struct work_struct *work) mutex_lock(&priv->buffer_mutex); priv->command_enqueued = false; - ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer, - sizeof(priv->data_buffer), 0); - + ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, + sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); if (ret > 0) { priv->response_length = ret; @@ -80,7 +110,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip, mutex_init(&priv->buffer_mutex); timer_setup(&priv->user_read_timer, user_reader_timeout, 0); INIT_WORK(&priv->timeout_work, tpm_timeout_work); - INIT_WORK(&priv->async_work, tpm_async_work); + INIT_WORK(&priv->async_work, tpm_dev_async_work); init_waitqueue_head(&priv->async_wait); file->private_data = priv; } @@ -183,8 +213,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, return size; } - ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer, - sizeof(priv->data_buffer), 0); + ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, + sizeof(priv->data_buffer)); tpm_put_ops(priv->chip); if (ret > 0) { diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index d9439f9abe78..83ece5639f86 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -62,137 +62,22 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -static int tpm_validate_command(struct tpm_chip *chip, - struct tpm_space *space, - const u8 *cmd, - size_t len) -{ - const struct tpm_input_header *header = (const void *)cmd; - int i; - u32 cc; - u32 attrs; - unsigned int nr_handles; - - if (len < TPM_HEADER_SIZE) - return -EINVAL; - - if (!space) - return 0; - - if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) { - cc = be32_to_cpu(header->ordinal); - - i = tpm2_find_cc(chip, cc); - if (i < 0) { - dev_dbg(&chip->dev, "0x%04X is an invalid command\n", - cc); - return -EOPNOTSUPP; - } - - attrs = chip->cc_attrs_tbl[i]; - nr_handles = - 4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0)); - if (len < TPM_HEADER_SIZE + 4 * nr_handles) - goto err_len; - } - - return 0; -err_len: - dev_dbg(&chip->dev, - "%s: insufficient command length %zu", __func__, len); - return -EINVAL; -} - -static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags) +static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz) { - int rc; - - if (flags & TPM_TRANSMIT_NESTED) - return 0; - - if (!chip->ops->request_locality) - return 0; - - rc = chip->ops->request_locality(chip, 0); - if (rc < 0) - return rc; - - chip->locality = rc; - - return 0; -} - -static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags) -{ - int rc; - - if (flags & TPM_TRANSMIT_NESTED) - return; - - if (!chip->ops->relinquish_locality) - return; - - rc = chip->ops->relinquish_locality(chip, chip->locality); - if (rc) - dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); - - chip->locality = -1; -} - -static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags) -{ - if (flags & TPM_TRANSMIT_NESTED) - 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_NESTED) - 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, - unsigned int flags) -{ - struct tpm_output_header *header = (void *)buf; + struct tpm_header *header = buf; int rc; ssize_t len = 0; u32 count, ordinal; unsigned long stop; - bool need_locality; - 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 sizeof(*header); - } + if (bufsiz < TPM_HEADER_SIZE) + return -EINVAL; if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; - count = be32_to_cpu(*((__be32 *) (buf + 2))); - ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); + count = be32_to_cpu(header->length); + ordinal = be32_to_cpu(header->ordinal); if (count == 0) return -ENODATA; if (count > bufsiz) { @@ -201,37 +86,21 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, return -E2BIG; } - 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); - - /* Store the decision as chip->locality will be changed. */ - need_locality = chip->locality == -1; - - if (need_locality) { - rc = tpm_request_locality(chip, flags); - if (rc < 0) { - need_locality = false; - goto out_locality; - } - } - - rc = tpm_cmd_ready(chip, flags); - if (rc) - goto out_locality; - - rc = tpm2_prepare_space(chip, space, ordinal, buf); - if (rc) - goto out; - rc = chip->ops->send(chip, buf, count); if (rc < 0) { if (rc != -EPIPE) dev_err(&chip->dev, - "%s: tpm_send: error %d\n", __func__, rc); - goto out; + "%s: send(): error %d\n", __func__, rc); + return rc; + } + + /* A sanity check. send() should just return zero on success e.g. + * not the command length. + */ + if (rc > 0) { + dev_warn(&chip->dev, + "%s: send(): invalid value %d\n", __func__, rc); + rc = 0; } if (chip->flags & TPM_CHIP_FLAG_IRQ) @@ -246,8 +115,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, if (chip->ops->req_canceled(chip, status)) { dev_err(&chip->dev, "Operation Canceled\n"); - rc = -ECANCELED; - goto out; + return -ECANCELED; } tpm_msleep(TPM_TIMEOUT_POLL); @@ -256,77 +124,45 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, chip->ops->cancel(chip); dev_err(&chip->dev, "Operation Timed out\n"); - rc = -ETIME; - goto out; + return -ETIME; out_recv: len = chip->ops->recv(chip, buf, bufsiz); if (len < 0) { rc = len; - dev_err(&chip->dev, - "tpm_transmit: tpm_recv: error %d\n", rc); - goto out; - } else if (len < TPM_HEADER_SIZE) { + dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %d\n", rc); + } else if (len < TPM_HEADER_SIZE || len != be32_to_cpu(header->length)) rc = -EFAULT; - goto out; - } - if (len != be32_to_cpu(header->length)) { - rc = -EFAULT; - goto out; - } - - rc = tpm2_commit_space(chip, space, ordinal, buf, &len); - if (rc) - dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc); - -out: - /* may fail but do not override previous error value in rc */ - tpm_go_idle(chip, flags); - -out_locality: - if (need_locality) - tpm_relinquish_locality(chip, flags); - - if (chip->ops->clk_enable != NULL) - chip->ops->clk_enable(chip, false); - - if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED)) - mutex_unlock(&chip->tpm_mutex); return rc ? rc : len; } /** * tpm_transmit - Internal kernel interface to transmit TPM commands. + * @chip: a TPM chip to use + * @buf: a TPM command buffer + * @bufsiz: length of the TPM command buffer * - * @chip: TPM chip to use - * @space: tpm space - * @buf: TPM command buffer - * @bufsiz: length of the TPM command buffer - * @flags: tpm transmit flags - bitmap - * - * A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY - * returns from the TPM and retransmits the command after a delay up - * to a maximum wait of TPM2_DURATION_LONG. + * A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from + * the TPM and retransmits the command after a delay up to a maximum wait of + * TPM2_DURATION_LONG. * - * Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2 - * only + * Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0 + * only. * * Return: - * the length of the return when the operation is successful. - * A negative number for system errors (errno). + * * The response length - OK + * * -errno - A system error */ -ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, - u8 *buf, size_t bufsiz, unsigned int flags) +ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz) { - struct tpm_output_header *header = (struct tpm_output_header *)buf; + struct tpm_header *header = (struct tpm_header *)buf; /* space for header and handles */ u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)]; unsigned int delay_msec = TPM2_DURATION_SHORT; u32 rc = 0; ssize_t ret; - const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE, - bufsiz); + const size_t save_size = min(sizeof(save), bufsiz); /* the command code is where the return code will be */ u32 cc = be32_to_cpu(header->return_code); @@ -338,7 +174,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, memcpy(save, buf, save_size); for (;;) { - ret = tpm_try_transmit(chip, space, buf, bufsiz, flags); + ret = tpm_try_transmit(chip, buf, bufsiz); if (ret < 0) break; rc = be32_to_cpu(header->return_code); @@ -365,39 +201,33 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, } return ret; } + /** * tpm_transmit_cmd - send a tpm command to the device - * The function extracts tpm out header return code - * - * @chip: TPM chip to use - * @space: tpm space - * @buf: TPM command buffer - * @bufsiz: length of the buffer - * @min_rsp_body_length: minimum expected length of response body - * @flags: tpm transmit flags - bitmap - * @desc: command description used in the error message + * @chip: a TPM chip to use + * @buf: a TPM command buffer + * @min_rsp_body_length: minimum expected length of response body + * @desc: command description used in the error message * * Return: - * 0 when the operation is successful. - * A negative number for system errors (errno). - * A positive number for a TPM error. + * * 0 - OK + * * -errno - A system error + * * TPM_RC - A TPM error */ -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, - void *buf, size_t bufsiz, - size_t min_rsp_body_length, unsigned int flags, - const char *desc) +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf, + size_t min_rsp_body_length, const char *desc) { - const struct tpm_output_header *header = buf; + const struct tpm_header *header = (struct tpm_header *)buf->data; int err; ssize_t len; - len = tpm_transmit(chip, space, buf, bufsiz, flags); + len = tpm_transmit(chip, buf->data, PAGE_SIZE); if (len < 0) return len; err = be32_to_cpu(header->return_code); if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED - && desc) + && err != TPM2_RC_TESTING && desc) dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, desc); if (err) @@ -451,11 +281,12 @@ EXPORT_SYMBOL_GPL(tpm_is_tpm2); * 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 + * @digest: the PCR bank and buffer current PCR value is written to * * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) +int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, + struct tpm_digest *digest) { int rc; @@ -464,9 +295,9 @@ int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) - rc = tpm2_pcr_read(chip, pcr_idx, res_buf); + rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL); else - rc = tpm1_pcr_read(chip, pcr_idx, res_buf); + rc = tpm1_pcr_read(chip, pcr_idx, digest->digest); tpm_put_ops(chip); return rc; @@ -477,41 +308,34 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); * 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 + * @digests: array of tpm_digest structures used to extend PCRs * - * 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. + * Note: callers must pass a digest for every allocated PCR bank, in the same + * order of the banks in chip->allocated_banks. * * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash) +int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, + struct tpm_digest *digests) { int rc; - struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)]; - u32 count = 0; int i; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; - if (chip->flags & TPM_CHIP_FLAG_TPM2) { - memset(digest_list, 0, sizeof(digest_list)); - - for (i = 0; i < ARRAY_SIZE(chip->active_banks) && - chip->active_banks[i] != TPM2_ALG_ERROR; i++) { - digest_list[i].alg_id = chip->active_banks[i]; - memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE); - count++; - } + for (i = 0; i < chip->nr_allocated_banks; i++) + if (digests[i].alg_id != chip->allocated_banks[i].alg_id) + return -EINVAL; - rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list); + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + rc = tpm2_pcr_extend(chip, pcr_idx, digests); tpm_put_ops(chip); return rc; } - rc = tpm1_pcr_extend(chip, pcr_idx, hash, + rc = tpm1_pcr_extend(chip, pcr_idx, digests[0].digest, "attempting extend a PCR value"); tpm_put_ops(chip); return rc; @@ -528,14 +352,21 @@ EXPORT_SYMBOL_GPL(tpm_pcr_extend); */ int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { + struct tpm_buf buf; int rc; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; - rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0, - "attempting to a send a command"); + rc = tpm_buf_init(&buf, 0, 0); + if (rc) + goto out; + + memcpy(buf.data, cmd, buflen); + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to a send a command"); + tpm_buf_destroy(&buf); +out: tpm_put_ops(chip); return rc; } @@ -571,10 +402,16 @@ int tpm_pm_suspend(struct device *dev) if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) return 0; - if (chip->flags & TPM_CHIP_FLAG_TPM2) - tpm2_shutdown(chip, TPM2_SU_STATE); - else + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + mutex_lock(&chip->tpm_mutex); + if (!tpm_chip_start(chip)) { + tpm2_shutdown(chip, TPM2_SU_STATE); + tpm_chip_stop(chip); + } + mutex_unlock(&chip->tpm_mutex); + } else { rc = tpm1_pm_suspend(chip, tpm_suspend_pcr); + } return rc; } diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index b88e08ec2c59..533a260d744e 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -39,7 +39,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, { struct tpm_buf tpm_buf; struct tpm_readpubek_out *out; - ssize_t rc; int i; char *str = buf; struct tpm_chip *chip = to_tpm_chip(dev); @@ -47,19 +46,17 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, memset(&anti_replay, 0, sizeof(anti_replay)); - rc = tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK); - if (rc) - return rc; + if (tpm_try_get_ops(chip)) + return 0; + + if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK)) + goto out_ops; tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay)); - rc = tpm_transmit_cmd(chip, NULL, tpm_buf.data, PAGE_SIZE, - READ_PUBEK_RESULT_MIN_BODY_SIZE, 0, - "attempting to read the PUBEK"); - if (rc) { - tpm_buf_destroy(&tpm_buf); - return 0; - } + if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE, + "attempting to read the PUBEK")) + goto out_buf; out = (struct tpm_readpubek_out *)&tpm_buf.data[10]; str += @@ -90,9 +87,11 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, str += sprintf(str, "\n"); } - rc = str - buf; +out_buf: tpm_buf_destroy(&tpm_buf); - return rc; +out_ops: + tpm_put_ops(chip); + return str - buf; } static DEVICE_ATTR_RO(pubek); @@ -101,27 +100,32 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, { cap_t cap; u8 digest[TPM_DIGEST_SIZE]; - ssize_t rc; u32 i, j, num_pcrs; char *str = buf; struct tpm_chip *chip = to_tpm_chip(dev); - rc = tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap, - "attempting to determine the number of PCRS", - sizeof(cap.num_pcrs)); - if (rc) + if (tpm_try_get_ops(chip)) return 0; + if (tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap, + "attempting to determine the number of PCRS", + sizeof(cap.num_pcrs))) { + tpm_put_ops(chip); + return 0; + } + num_pcrs = be32_to_cpu(cap.num_pcrs); for (i = 0; i < num_pcrs; i++) { - rc = tpm1_pcr_read(chip, i, digest); - if (rc) + if (tpm1_pcr_read(chip, i, digest)) { + str = buf; break; + } str += sprintf(str, "PCR-%02d: ", i); for (j = 0; j < TPM_DIGEST_SIZE; j++) str += sprintf(str, "%02X ", digest[j]); str += sprintf(str, "\n"); } + tpm_put_ops(chip); return str - buf; } static DEVICE_ATTR_RO(pcrs); @@ -129,16 +133,21 @@ static DEVICE_ATTR_RO(pcrs); static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct tpm_chip *chip = to_tpm_chip(dev); + ssize_t rc = 0; cap_t cap; - ssize_t rc; - rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, - "attempting to determine the permanent enabled state", - sizeof(cap.perm_flags)); - if (rc) + if (tpm_try_get_ops(chip)) return 0; + if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap, + "attempting to determine the permanent enabled state", + sizeof(cap.perm_flags))) + goto out_ops; + rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); +out_ops: + tpm_put_ops(chip); return rc; } static DEVICE_ATTR_RO(enabled); @@ -146,16 +155,21 @@ static DEVICE_ATTR_RO(enabled); static ssize_t active_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct tpm_chip *chip = to_tpm_chip(dev); + ssize_t rc = 0; cap_t cap; - ssize_t rc; - rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, - "attempting to determine the permanent active state", - sizeof(cap.perm_flags)); - if (rc) + if (tpm_try_get_ops(chip)) return 0; + if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap, + "attempting to determine the permanent active state", + sizeof(cap.perm_flags))) + goto out_ops; + rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); +out_ops: + tpm_put_ops(chip); return rc; } static DEVICE_ATTR_RO(active); @@ -163,16 +177,21 @@ static DEVICE_ATTR_RO(active); static ssize_t owned_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct tpm_chip *chip = to_tpm_chip(dev); + ssize_t rc = 0; cap_t cap; - ssize_t rc; - rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, - "attempting to determine the owner state", - sizeof(cap.owned)); - if (rc) + if (tpm_try_get_ops(chip)) return 0; + if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, + "attempting to determine the owner state", + sizeof(cap.owned))) + goto out_ops; + rc = sprintf(buf, "%d\n", cap.owned); +out_ops: + tpm_put_ops(chip); return rc; } static DEVICE_ATTR_RO(owned); @@ -180,16 +199,21 @@ static DEVICE_ATTR_RO(owned); static ssize_t temp_deactivated_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct tpm_chip *chip = to_tpm_chip(dev); + ssize_t rc = 0; cap_t cap; - ssize_t rc; - rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, - "attempting to determine the temporary state", - sizeof(cap.stclear_flags)); - if (rc) + if (tpm_try_get_ops(chip)) return 0; + if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, + "attempting to determine the temporary state", + sizeof(cap.stclear_flags))) + goto out_ops; + rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); +out_ops: + tpm_put_ops(chip); return rc; } static DEVICE_ATTR_RO(temp_deactivated); @@ -198,15 +222,18 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tpm_chip *chip = to_tpm_chip(dev); - cap_t cap; - ssize_t rc; + ssize_t rc = 0; char *str = buf; + cap_t cap; - rc = tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, - "attempting to determine the manufacturer", - sizeof(cap.manufacturer_id)); - if (rc) + if (tpm_try_get_ops(chip)) return 0; + + if (tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, + "attempting to determine the manufacturer", + sizeof(cap.manufacturer_id))) + goto out_ops; + str += sprintf(str, "Manufacturer: 0x%x\n", be32_to_cpu(cap.manufacturer_id)); @@ -223,11 +250,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, cap.tpm_version_1_2.revMinor); } else { /* Otherwise just use TPM_STRUCT_VER */ - rc = tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap, - "attempting to determine the 1.1 version", - sizeof(cap.tpm_version)); - if (rc) - return 0; + if (tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap, + "attempting to determine the 1.1 version", + sizeof(cap.tpm_version))) + goto out_ops; str += sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", cap.tpm_version.Major, @@ -235,8 +261,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, cap.tpm_version.revMajor, cap.tpm_version.revMinor); } - - return str - buf; + rc = str - buf; +out_ops: + tpm_put_ops(chip); + return rc; } static DEVICE_ATTR_RO(caps); @@ -244,10 +272,12 @@ static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tpm_chip *chip = to_tpm_chip(dev); - if (chip == NULL) + + if (tpm_try_get_ops(chip)) return 0; chip->ops->cancel(chip); + tpm_put_ops(chip); return count; } static DEVICE_ATTR_WO(cancel); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index f27d1f38a93d..2cce072f25b5 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -25,30 +25,22 @@ #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> #include <linux/io.h> #include <linux/tpm.h> -#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 #include <asm/intel-family.h> #endif -enum tpm_const { - TPM_MINOR = 224, /* officially assigned */ - TPM_BUFSIZE = 4096, - TPM_NUM_DEVICES = 65536, - TPM_RETRY = 50, /* 5 seconds */ - TPM_NUM_EVENT_LOG_FILES = 3, -}; +#define TPM_MINOR 224 /* officially assigned */ +#define TPM_BUFSIZE 4096 +#define TPM_NUM_DEVICES 65536 +#define TPM_RETRY 50 enum tpm_timeout { TPM_TIMEOUT = 5, /* msecs */ @@ -65,16 +57,6 @@ enum tpm_addr { TPM_ADDR = 0x4E, }; -/* Indexes the duration array */ -enum tpm_duration { - TPM_SHORT = 0, - TPM_MEDIUM = 1, - TPM_LONG = 2, - TPM_LONG_LONG = 3, - TPM_UNDEFINED, - TPM_NUM_DURATIONS = TPM_UNDEFINED, -}; - #define TPM_WARN_RETRY 0x800 #define TPM_WARN_DOING_SELFTEST 0x802 #define TPM_ERR_DEACTIVATED 0x6 @@ -122,17 +104,6 @@ enum tpm2_return_codes { TPM2_RC_RETRY = 0x0922, }; -enum tpm2_algorithms { - TPM2_ALG_ERROR = 0x0000, - TPM2_ALG_SHA1 = 0x0004, - TPM2_ALG_KEYEDHASH = 0x0008, - TPM2_ALG_SHA256 = 0x000B, - TPM2_ALG_SHA384 = 0x000C, - TPM2_ALG_SHA512 = 0x000D, - TPM2_ALG_NULL = 0x0010, - TPM2_ALG_SM3_256 = 0x0012, -}; - enum tpm2_command_codes { TPM2_CC_FIRST = 0x011F, TPM2_CC_HIERARCHY_CONTROL = 0x0121, @@ -190,15 +161,6 @@ enum tpm2_cc_attrs { #define TPM_VID_WINBOND 0x1050 #define TPM_VID_STM 0x104A -#define TPM_PPI_VERSION_LEN 3 - -struct tpm_space { - u32 context_tbl[3]; - u8 *context_buf; - u32 session_tbl[3]; - u8 *session_buf; -}; - enum tpm_chip_flags { TPM_CHIP_FLAG_TPM2 = BIT(1), TPM_CHIP_FLAG_IRQ = BIT(2), @@ -207,82 +169,15 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), }; -struct tpm_bios_log { - void *bios_event_log; - void *bios_event_log_end; -}; - -struct tpm_chip_seqops { - struct tpm_chip *chip; - const struct seq_operations *seqops; -}; - -struct tpm_chip { - struct device dev; - struct device devs; - struct cdev cdev; - struct cdev cdevs; - - /* A driver callback under ops cannot be run unless ops_sem is held - * (sometimes implicitly, eg for the sysfs code). ops becomes null - * when the driver is unregistered, see tpm_try_get_ops. - */ - struct rw_semaphore ops_sem; - const struct tpm_class_ops *ops; - - struct tpm_bios_log log; - struct tpm_chip_seqops bin_log_seqops; - struct tpm_chip_seqops ascii_log_seqops; - - unsigned int flags; - - 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 */ - unsigned long timeout_b; /* jiffies */ - unsigned long timeout_c; /* jiffies */ - unsigned long timeout_d; /* jiffies */ - bool timeout_adjusted; - unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */ - bool duration_adjusted; - - struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES]; - - const struct attribute_group *groups[3]; - unsigned int groups_cnt; - - u16 active_banks[7]; -#ifdef CONFIG_ACPI - acpi_handle acpi_dev_handle; - char ppi_version[TPM_PPI_VERSION_LEN + 1]; -#endif /* CONFIG_ACPI */ - - struct tpm_space work_space; - u32 nr_commands; - u32 *cc_attrs_tbl; - - /* active locality */ - int locality; -}; - #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) -struct tpm_input_header { - __be16 tag; - __be32 length; - __be32 ordinal; -} __packed; - -struct tpm_output_header { - __be16 tag; - __be32 length; - __be32 return_code; +struct tpm_header { + __be16 tag; + __be32 length; + union { + __be32 ordinal; + __be32 return_code; + }; } __packed; #define TPM_TAG_RQU_COMMAND 193 @@ -401,8 +296,8 @@ struct tpm_buf { 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; + struct tpm_header *head = (struct tpm_header *)buf->data; + head->tag = cpu_to_be16(tag); head->length = cpu_to_be32(sizeof(*head)); head->ordinal = cpu_to_be32(ordinal); @@ -428,14 +323,14 @@ static inline void tpm_buf_destroy(struct tpm_buf *buf) static inline u32 tpm_buf_length(struct tpm_buf *buf) { - struct tpm_input_header *head = (struct tpm_input_header *) buf->data; + struct tpm_header *head = (struct tpm_header *)buf->data; return be32_to_cpu(head->length); } static inline u16 tpm_buf_tag(struct tpm_buf *buf) { - struct tpm_input_header *head = (struct tpm_input_header *) buf->data; + struct tpm_header *head = (struct tpm_header *)buf->data; return be16_to_cpu(head->tag); } @@ -444,7 +339,7 @@ static inline void tpm_buf_append(struct tpm_buf *buf, const unsigned char *new_data, unsigned int new_len) { - struct tpm_input_header *head = (struct tpm_input_header *) buf->data; + struct tpm_header *head = (struct tpm_header *)buf->data; u32 len = tpm_buf_length(buf); /* Return silently if overflow has already happened. */ @@ -487,25 +382,9 @@ extern const struct file_operations tpm_fops; extern const struct file_operations tpmrm_fops; extern struct idr dev_nums_idr; -/** - * enum tpm_transmit_flags - flags for tpm_transmit() - * - * @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_NESTED = BIT(1), -}; - -ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, - u8 *buf, size_t bufsiz, unsigned int flags); -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, - void *buf, size_t bufsiz, - size_t min_rsp_body_length, unsigned int flags, - const char *desc); +ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz); +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf, + size_t min_rsp_body_length, const char *desc); int tpm_get_timeouts(struct tpm_chip *); int tpm_auto_startup(struct tpm_chip *chip); @@ -530,6 +409,8 @@ static inline void tpm_msleep(unsigned int delay_msec) delay_msec * 1000); }; +int tpm_chip_start(struct tpm_chip *chip); +void tpm_chip_stop(struct tpm_chip *chip); struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip); __must_check int tpm_try_get_ops(struct tpm_chip *chip); void tpm_put_ops(struct tpm_chip *chip); @@ -558,12 +439,12 @@ static inline u32 tpm2_rc_value(u32 rc) } int tpm2_get_timeouts(struct tpm_chip *chip); -int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf); -int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count, - struct tpm2_digest *digests); +int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, + struct tpm_digest *digest, u16 *digest_size_ptr); +int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, + struct tpm_digest *digests); 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); +void tpm2_flush_context(struct tpm_chip *chip, u32 handle); int tpm2_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options); @@ -580,10 +461,11 @@ int tpm2_probe(struct tpm_chip *chip); int tpm2_find_cc(struct tpm_chip *chip, u32 cc); int tpm2_init_space(struct tpm_space *space); void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space); -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); +void tpm2_flush_space(struct tpm_chip *chip); +int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd, + size_t cmdsiz); +int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf, + size_t *bufsiz); int tpm_bios_log_setup(struct tpm_chip *chip); void tpm_bios_log_teardown(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c index 6f306338953b..85dcf2654d11 100644 --- a/drivers/char/tpm/tpm1-cmd.c +++ b/drivers/char/tpm/tpm1-cmd.c @@ -334,11 +334,8 @@ static int tpm1_startup(struct tpm_chip *chip) 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"); - + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM"); tpm_buf_destroy(&buf); - return rc; } @@ -380,8 +377,7 @@ int tpm1_get_timeouts(struct tpm_chip *chip) * of misreporting. */ if (chip->ops->update_timeouts) - chip->timeout_adjusted = - chip->ops->update_timeouts(chip, timeout_eff); + chip->ops->update_timeouts(chip, timeout_eff); if (!chip->timeout_adjusted) { /* Restore default if chip reported 0 */ @@ -462,9 +458,7 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash, tpm_buf_append_u32(&buf, pcr_idx); tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, - TPM_DIGEST_SIZE, 0, log_msg); - + rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg); tpm_buf_destroy(&buf); return rc; } @@ -494,11 +488,9 @@ ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, tpm_buf_append_u32(&buf, 4); tpm_buf_append_u32(&buf, subcap_id); } - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, - min_cap_length, 0, desc); + rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc); if (!rc) *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4]; - tpm_buf_destroy(&buf); return rc; } @@ -537,8 +529,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) do { tpm_buf_append_u32(&buf, num_bytes); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, - sizeof(out->rng_data_len), 0, + rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len), "attempting get random"); if (rc) goto out; @@ -583,8 +574,7 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) tpm_buf_append_u32(&buf, pcr_idx); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, - TPM_DIGEST_SIZE, 0, + rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, "attempting to read a pcr value"); if (rc) goto out; @@ -618,11 +608,8 @@ static int tpm1_continue_selftest(struct tpm_chip *chip) if (rc) return rc; - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, - 0, 0, "continue selftest"); - + rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest"); tpm_buf_destroy(&buf); - return rc; } @@ -709,6 +696,18 @@ int tpm1_auto_startup(struct tpm_chip *chip) goto out; } + chip->allocated_banks = kcalloc(1, sizeof(*chip->allocated_banks), + GFP_KERNEL); + if (!chip->allocated_banks) { + rc = -ENOMEM; + goto out; + } + + chip->allocated_banks[0].alg_id = TPM_ALG_SHA1; + chip->allocated_banks[0].digest_size = hash_digest_size[HASH_ALGO_SHA1]; + chip->allocated_banks[0].crypto_id = HASH_ALGO_SHA1; + chip->nr_allocated_banks = 1; + return rc; out: if (rc > 0) @@ -747,9 +746,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr) return rc; /* now do the actual savestate */ for (try = 0; try < TPM_RETRY; try++) { - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, - 0, 0, NULL); - + rc = tpm_transmit_cmd(chip, &buf, 0, NULL); /* * If the TPM indicates that it is too busy to respond to * this command then retry before giving up. It can take diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index a6bec13afa69..e74c5b7b64bf 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -33,11 +33,11 @@ struct tpm2_hash { }; static struct tpm2_hash tpm2_hash_map[] = { - {HASH_ALGO_SHA1, TPM2_ALG_SHA1}, - {HASH_ALGO_SHA256, TPM2_ALG_SHA256}, - {HASH_ALGO_SHA384, TPM2_ALG_SHA384}, - {HASH_ALGO_SHA512, TPM2_ALG_SHA512}, - {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256}, + {HASH_ALGO_SHA1, TPM_ALG_SHA1}, + {HASH_ALGO_SHA256, TPM_ALG_SHA256}, + {HASH_ALGO_SHA384, TPM_ALG_SHA384}, + {HASH_ALGO_SHA512, TPM_ALG_SHA512}, + {HASH_ALGO_SM3_256, TPM_ALG_SM3_256}, }; int tpm2_get_timeouts(struct tpm_chip *chip) @@ -171,20 +171,36 @@ struct tpm2_pcr_read_out { * tpm2_pcr_read() - read a PCR value * @chip: TPM chip to use. * @pcr_idx: index of the PCR to read. - * @res_buf: buffer to store the resulting hash. + * @digest: PCR bank and buffer current PCR value is written to. + * @digest_size_ptr: pointer to variable that stores the digest size. * * Return: Same as with tpm_transmit_cmd. */ -int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) +int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, + struct tpm_digest *digest, u16 *digest_size_ptr) { + int i; int rc; struct tpm_buf buf; struct tpm2_pcr_read_out *out; u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0}; + u16 digest_size; + u16 expected_digest_size = 0; if (pcr_idx >= TPM2_PLATFORM_PCR) return -EINVAL; + if (!digest_size_ptr) { + for (i = 0; i < chip->nr_allocated_banks && + chip->allocated_banks[i].alg_id != digest->alg_id; i++) + ; + + if (i == chip->nr_allocated_banks) + return -EINVAL; + + expected_digest_size = chip->allocated_banks[i].digest_size; + } + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ); if (rc) return rc; @@ -192,18 +208,28 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); tpm_buf_append_u32(&buf, 1); - tpm_buf_append_u16(&buf, TPM2_ALG_SHA1); + tpm_buf_append_u16(&buf, digest->alg_id); 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); + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value"); + if (rc) + goto out; + + out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE]; + digest_size = be16_to_cpu(out->digest_size); + if (digest_size > sizeof(digest->digest) || + (!digest_size_ptr && digest_size != expected_digest_size)) { + rc = -EINVAL; + goto out; } + if (digest_size_ptr) + *digest_size_ptr = digest_size; + + memcpy(digest->digest, out->digest, digest_size); +out: tpm_buf_destroy(&buf); return rc; } @@ -220,22 +246,17 @@ struct tpm2_null_auth_area { * * @chip: TPM chip to use. * @pcr_idx: index of the PCR. - * @count: number of digests passed. * @digests: list of pcr banks and corresponding digest values to extend. * * Return: Same as with tpm_transmit_cmd. */ -int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count, - struct tpm2_digest *digests) +int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, + struct tpm_digest *digests) { struct tpm_buf buf; struct tpm2_null_auth_area auth_area; int rc; int i; - int j; - - if (count > ARRAY_SIZE(chip->active_banks)) - return -EINVAL; rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND); if (rc) @@ -251,21 +272,15 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count, tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area)); tpm_buf_append(&buf, (const unsigned char *)&auth_area, sizeof(auth_area)); - tpm_buf_append_u32(&buf, count); - - for (i = 0; i < count; i++) { - for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) { - if (digests[i].alg_id != tpm2_hash_map[j].tpm_id) - continue; - tpm_buf_append_u16(&buf, digests[i].alg_id); - tpm_buf_append(&buf, (const unsigned char - *)&digests[i].digest, - hash_digest_size[tpm2_hash_map[j].crypto_id]); - } + tpm_buf_append_u32(&buf, chip->nr_allocated_banks); + + for (i = 0; i < chip->nr_allocated_banks; i++) { + tpm_buf_append_u16(&buf, digests[i].alg_id); + tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest, + chip->allocated_banks[i].digest_size); } - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, - "attempting extend a PCR value"); + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value"); tpm_buf_destroy(&buf); @@ -309,10 +324,10 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) 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, + err = tpm_transmit_cmd(chip, &buf, offsetof(struct tpm2_get_random_out, buffer), - 0, "attempting get random"); + "attempting get random"); if (err) goto out; @@ -341,14 +356,11 @@ out: } /** - * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command + * tpm2_flush_context() - execute a TPM2_FlushContext command * @chip: TPM chip to use * @handle: context handle - * @flags: tpm transmit flags - bitmap - * */ -void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, - unsigned int flags) +void tpm2_flush_context(struct tpm_chip *chip, u32 handle) { struct tpm_buf buf; int rc; @@ -362,9 +374,7 @@ void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, tpm_buf_append_u32(&buf, handle); - (void) tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, flags, - "flushing context"); - + tpm_transmit_cmd(chip, &buf, 0, "flushing context"); tpm_buf_destroy(&buf); } @@ -449,7 +459,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, /* public */ tpm_buf_append_u16(&buf, 14 + options->policydigest_len); - tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH); + tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH); tpm_buf_append_u16(&buf, hash); /* policy */ @@ -464,7 +474,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, } /* public parameters */ - tpm_buf_append_u16(&buf, TPM2_ALG_NULL); + tpm_buf_append_u16(&buf, TPM_ALG_NULL); tpm_buf_append_u16(&buf, 0); /* outside info */ @@ -478,8 +488,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0, - "sealing data"); + rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data"); if (rc) goto out; @@ -516,7 +525,6 @@ out: * @payload: the key data in clear and encrypted form * @options: authentication values and other options * @blob_handle: returned blob handle - * @flags: tpm transmit flags * * Return: 0 on success. * -E2BIG on wrong payload size. @@ -526,7 +534,7 @@ out: static int tpm2_load_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options, - u32 *blob_handle, unsigned int flags) + u32 *blob_handle) { struct tpm_buf buf; unsigned int private_len; @@ -561,8 +569,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags, - "loading blob"); + rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob"); if (!rc) *blob_handle = be32_to_cpup( (__be32 *) &buf.data[TPM_HEADER_SIZE]); @@ -583,7 +590,6 @@ out: * @payload: the key data in clear and encrypted form * @options: authentication values and other options * @blob_handle: blob handle - * @flags: tpm_transmit_cmd flags * * Return: 0 on success * -EPERM on tpm error status @@ -592,7 +598,7 @@ out: static int tpm2_unseal_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options, - u32 blob_handle, unsigned int flags) + u32 blob_handle) { struct tpm_buf buf; u16 data_len; @@ -612,8 +618,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, options->blobauth /* hmac */, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags, - "unsealing"); + rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); if (rc > 0) rc = -EPERM; @@ -657,17 +662,12 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, u32 blob_handle; int rc; - mutex_lock(&chip->tpm_mutex); - rc = tpm2_load_cmd(chip, payload, options, &blob_handle, - TPM_TRANSMIT_UNLOCKED); + rc = tpm2_load_cmd(chip, payload, options, &blob_handle); if (rc) - goto out; + return rc; - rc = tpm2_unseal_cmd(chip, payload, options, blob_handle, - TPM_TRANSMIT_UNLOCKED); - tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED); -out: - mutex_unlock(&chip->tpm_mutex); + rc = tpm2_unseal_cmd(chip, payload, options, blob_handle); + tpm2_flush_context(chip, blob_handle); return rc; } @@ -703,7 +703,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, 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); + rc = tpm_transmit_cmd(chip, &buf, 0, NULL); if (!rc) { out = (struct tpm2_get_cap_out *) &buf.data[TPM_HEADER_SIZE]; @@ -733,8 +733,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) 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_transmit_cmd(chip, &buf, 0, "stopping the TPM"); tpm_buf_destroy(&buf); } @@ -763,7 +762,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip) return rc; tpm_buf_append_u8(&buf, full); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting the self test"); tpm_buf_destroy(&buf); @@ -790,7 +789,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip) */ int tpm2_probe(struct tpm_chip *chip) { - struct tpm_output_header *out; + struct tpm_header *out; struct tpm_buf buf; int rc; @@ -800,10 +799,10 @@ int tpm2_probe(struct tpm_chip *chip) 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); + rc = tpm_transmit_cmd(chip, &buf, 0, NULL); /* We ignore TPM return codes on purpose. */ if (rc >= 0) { - out = (struct tpm_output_header *)buf.data; + out = (struct tpm_header *)buf.data; if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS) chip->flags |= TPM_CHIP_FLAG_TPM2; } @@ -812,6 +811,30 @@ int tpm2_probe(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm2_probe); +static int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index) +{ + struct tpm_bank_info *bank = chip->allocated_banks + bank_index; + struct tpm_digest digest = { .alg_id = bank->alg_id }; + int i; + + /* + * Avoid unnecessary PCR read operations to reduce overhead + * and obtain identifiers of the crypto subsystem. + */ + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { + enum hash_algo crypto_algo = tpm2_hash_map[i].crypto_id; + + if (bank->alg_id != tpm2_hash_map[i].tpm_id) + continue; + + bank->digest_size = hash_digest_size[crypto_algo]; + bank->crypto_id = crypto_algo; + return 0; + } + + return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size); +} + struct tpm2_pcr_selection { __be16 hash_alg; u8 size_of_select; @@ -825,8 +848,10 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) void *marker; void *end; void *pcr_select_offset; - unsigned int count; u32 sizeof_pcr_selection; + u32 nr_possible_banks; + u32 nr_alloc_banks = 0; + u16 hash_alg; u32 rsp_len; int rc; int i = 0; @@ -839,16 +864,18 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) tpm_buf_append_u32(&buf, 0); tpm_buf_append_u32(&buf, 1); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 9, 0, - "get tpm pcr allocation"); + rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation"); if (rc) goto out; - count = be32_to_cpup( + nr_possible_banks = be32_to_cpup( (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); - if (count > ARRAY_SIZE(chip->active_banks)) { - rc = -ENODEV; + chip->allocated_banks = kcalloc(nr_possible_banks, + sizeof(*chip->allocated_banks), + GFP_KERNEL); + if (!chip->allocated_banks) { + rc = -ENOMEM; goto out; } @@ -857,7 +884,7 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) rsp_len = be32_to_cpup((__be32 *)&buf.data[2]); end = &buf.data[rsp_len]; - for (i = 0; i < count; i++) { + for (i = 0; i < nr_possible_banks; i++) { pcr_select_offset = marker + offsetof(struct tpm2_pcr_selection, size_of_select); if (pcr_select_offset >= end) { @@ -866,17 +893,28 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) } memcpy(&pcr_selection, marker, sizeof(pcr_selection)); - chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg); + hash_alg = be16_to_cpu(pcr_selection.hash_alg); + + pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0, + pcr_selection.size_of_select); + if (pcr_select_offset) { + chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg; + + rc = tpm2_init_bank_info(chip, nr_alloc_banks); + if (rc < 0) + break; + + nr_alloc_banks++; + } + sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + sizeof(pcr_selection.size_of_select) + pcr_selection.size_of_select; marker = marker + sizeof_pcr_selection; } + chip->nr_allocated_banks = nr_alloc_banks; out: - if (i < ARRAY_SIZE(chip->active_banks)) - chip->active_banks[i] = TPM2_ALG_ERROR; - tpm_buf_destroy(&buf); return rc; @@ -911,8 +949,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) tpm_buf_append_u32(&buf, TPM2_CC_FIRST); tpm_buf_append_u32(&buf, nr_commands); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, - 9 + 4 * nr_commands, 0, NULL); + rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL); if (rc) { tpm_buf_destroy(&buf); goto out; @@ -969,8 +1006,7 @@ static int tpm2_startup(struct tpm_chip *chip) return rc; tpm_buf_append_u16(&buf, TPM2_SU_CLEAR); - rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, - "attempting to start the TPM"); + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM"); tpm_buf_destroy(&buf); return rc; diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index dcdfde3c253e..4a2773c3374f 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -38,8 +38,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_NESTED); + tpm2_flush_context(chip, space->session_tbl[i]); } } @@ -61,7 +60,10 @@ int tpm2_init_space(struct tpm_space *space) void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) { mutex_lock(&chip->tpm_mutex); - tpm2_flush_sessions(chip, space); + if (!tpm_chip_start(chip)) { + tpm2_flush_sessions(chip, space); + tpm_chip_stop(chip); + } mutex_unlock(&chip->tpm_mutex); kfree(space->context_buf); kfree(space->session_buf); @@ -83,8 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size); tpm_buf_append(&tbuf, &buf[*offset], body_size); - rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, - TPM_TRANSMIT_NESTED, NULL); + rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -132,8 +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_NESTED, NULL); + rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -162,15 +162,14 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, return 0; } -static void tpm2_flush_space(struct tpm_chip *chip) +void tpm2_flush_space(struct tpm_chip *chip) { struct tpm_space *space = &chip->work_space; int i; 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_NESTED); + tpm2_flush_context(chip, space->context_tbl[i]); tpm2_flush_sessions(chip, space); } @@ -264,14 +263,54 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd) return 0; } -int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, - u8 *cmd) +static int tpm_find_and_validate_cc(struct tpm_chip *chip, + struct tpm_space *space, + const void *cmd, size_t len) +{ + const struct tpm_header *header = (const void *)cmd; + int i; + u32 cc; + u32 attrs; + unsigned int nr_handles; + + if (len < TPM_HEADER_SIZE || !chip->nr_commands) + return -EINVAL; + + cc = be32_to_cpu(header->ordinal); + + i = tpm2_find_cc(chip, cc); + if (i < 0) { + dev_dbg(&chip->dev, "0x%04X is an invalid command\n", + cc); + return -EOPNOTSUPP; + } + + attrs = chip->cc_attrs_tbl[i]; + nr_handles = + 4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0)); + if (len < TPM_HEADER_SIZE + 4 * nr_handles) + goto err_len; + + return cc; +err_len: + dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__, + len); + return -EINVAL; +} + +int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd, + size_t cmdsiz) { int rc; + int cc; if (!space) return 0; + cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz); + if (cc < 0) + return cc; + memcpy(&chip->work_space.context_tbl, &space->context_tbl, sizeof(space->context_tbl)); memcpy(&chip->work_space.session_tbl, &space->session_tbl, @@ -291,6 +330,7 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, return rc; } + chip->last_cc = cc; return 0; } @@ -334,7 +374,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, size_t len) { struct tpm_space *space = &chip->work_space; - struct tpm_output_header *header = (void *)rsp; + struct tpm_header *header = (struct tpm_header *)rsp; u32 phandle; u32 phandle_type; u32 vhandle; @@ -377,7 +417,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_NESTED); + tpm2_flush_context(chip, phandle); dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, phandle); return -ENOMEM; @@ -394,7 +434,7 @@ static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp, size_t len) { struct tpm_space *space = &chip->work_space; - struct tpm_output_header *header = (void *)rsp; + struct tpm_header *header = (struct tpm_header *)rsp; struct tpm2_cap_handles *data; u32 phandle; u32 phandle_type; @@ -464,8 +504,7 @@ static int tpm2_save_space(struct tpm_chip *chip) } else if (rc) return rc; - tpm2_flush_context_cmd(chip, space->context_tbl[i], - TPM_TRANSMIT_NESTED); + tpm2_flush_context(chip, space->context_tbl[i]); space->context_tbl[i] = ~0; } @@ -490,30 +529,30 @@ static int tpm2_save_space(struct tpm_chip *chip) } int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, - u32 cc, u8 *buf, size_t *bufsiz) + void *buf, size_t *bufsiz) { - struct tpm_output_header *header = (void *)buf; + struct tpm_header *header = buf; int rc; if (!space) return 0; - rc = tpm2_map_response_header(chip, cc, buf, *bufsiz); + rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz); if (rc) { tpm2_flush_space(chip); - return rc; + goto out; } - rc = tpm2_map_response_body(chip, cc, buf, *bufsiz); + rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz); if (rc) { tpm2_flush_space(chip); - return rc; + goto out; } rc = tpm2_save_space(chip); if (rc) { tpm2_flush_space(chip); - return rc; + goto out; } *bufsiz = be32_to_cpu(header->length); @@ -526,4 +565,7 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE); return 0; +out: + dev_err(&chip->dev, "%s: error %d\n", __func__, rc); + return rc; } diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 66a14526aaf4..a290b30a0c35 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -105,7 +105,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) iowrite8(buf[i], priv->iobase); } - return count; + return 0; } static void tpm_atml_cancel(struct tpm_chip *chip) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 36952ef98f90..763fc7e6c005 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -287,19 +287,29 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) struct crb_priv *priv = dev_get_drvdata(&chip->dev); unsigned int expected; - /* sanity check */ - if (count < 6) + /* A sanity check that the upper layer wants to get at least the header + * as that is the minimum size for any TPM response. + */ + if (count < TPM_HEADER_SIZE) return -EIO; + /* If this bit is set, according to the spec, the TPM is in + * unrecoverable condition. + */ if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) return -EIO; - memcpy_fromio(buf, priv->rsp, 6); - expected = be32_to_cpup((__be32 *) &buf[2]); - if (expected > count || expected < 6) + /* Read the first 8 bytes in order to get the length of the response. + * We read exactly a quad word in order to make sure that the remaining + * reads will be aligned. + */ + memcpy_fromio(buf, priv->rsp, 8); + + expected = be32_to_cpup((__be32 *)&buf[2]); + if (expected > count || expected < TPM_HEADER_SIZE) return -EIO; - memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6); + memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8); return expected; } diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 95ce2e9ccdc6..8a7e80923091 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -46,7 +46,7 @@ struct priv_data { /* This is the amount we read on the first try. 25 was chosen to fit a * fair number of read responses in the buffer so a 2nd retry can be * avoided in small message cases. */ - u8 buffer[sizeof(struct tpm_output_header) + 25]; + u8 buffer[sizeof(struct tpm_header) + 25]; }; static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) @@ -65,15 +65,22 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) dev_dbg(&chip->dev, "%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, (int)min_t(size_t, 64, len), buf, len, status); - return status; + + if (status < 0) + return status; + + /* The upper layer does not support incomplete sends. */ + if (status != len) + return -E2BIG; + + return 0; } static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct priv_data *priv = dev_get_drvdata(&chip->dev); struct i2c_client *client = to_i2c_client(chip->dev.parent); - struct tpm_output_header *hdr = - (struct tpm_output_header *)priv->buffer; + struct tpm_header *hdr = (struct tpm_header *)priv->buffer; u32 expected_len; int rc; diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 9086edc9066b..3b4e9672ff6c 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -26,8 +26,7 @@ #include <linux/wait.h> #include "tpm.h" -/* max. buffer size supported by our TPM */ -#define TPM_BUFSIZE 1260 +#define TPM_I2C_INFINEON_BUFSIZE 1260 /* max. number of iterations after I2C NAK */ #define MAX_COUNT 3 @@ -63,11 +62,13 @@ enum i2c_chip_type { UNKNOWN, }; -/* Structure to store I2C TPM specific stuff */ struct tpm_inf_dev { struct i2c_client *client; int locality; - u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ + /* In addition to the data itself, the buffer must fit the 7-bit I2C + * address and the direction bit. + */ + u8 buf[TPM_I2C_INFINEON_BUFSIZE + 1]; struct tpm_chip *chip; enum i2c_chip_type chip_type; unsigned int adapterlimit; @@ -219,7 +220,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, .buf = tpm_dev.buf }; - if (len > TPM_BUFSIZE) + if (len > TPM_I2C_INFINEON_BUFSIZE) return -EINVAL; if (!tpm_dev.client->adapter->algo->master_xfer) @@ -527,8 +528,8 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) u8 retries = 0; u8 sts = TPM_STS_GO; - if (len > TPM_BUFSIZE) - return -E2BIG; /* command is too long for our tpm, sorry */ + if (len > TPM_I2C_INFINEON_BUFSIZE) + return -E2BIG; if (request_locality(chip, 0) < 0) return -EBUSY; @@ -587,7 +588,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) /* go and do it */ iic_tpm_write(TPM_STS(tpm_dev.locality), &sts, 1); - return len; + return 0; out_err: tpm_tis_i2c_ready(chip); /* The TPM needs some time to clean up here, diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 217f7f1cbde8..315a3b4548f7 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -35,14 +35,12 @@ #include "tpm.h" /* I2C interface offsets */ -#define TPM_STS 0x00 -#define TPM_BURST_COUNT 0x01 -#define TPM_DATA_FIFO_W 0x20 -#define TPM_DATA_FIFO_R 0x40 -#define TPM_VID_DID_RID 0x60 -/* TPM command header size */ -#define TPM_HEADER_SIZE 10 -#define TPM_RETRY 5 +#define TPM_STS 0x00 +#define TPM_BURST_COUNT 0x01 +#define TPM_DATA_FIFO_W 0x20 +#define TPM_DATA_FIFO_R 0x40 +#define TPM_VID_DID_RID 0x60 +#define TPM_I2C_RETRIES 5 /* * I2C bus device maximum buffer size w/o counting I2C address or command * i.e. max size required for I2C write is 34 = addr, command, 32 bytes data @@ -292,7 +290,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) dev_err(dev, "%s() count < header size\n", __func__); return -EIO; } - for (retries = 0; retries < TPM_RETRY; retries++) { + for (retries = 0; retries < TPM_I2C_RETRIES; retries++) { if (retries > 0) { /* if this is not the first trial, set responseRetry */ i2c_nuvoton_write_status(client, @@ -467,7 +465,7 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) } dev_dbg(dev, "%s() -> %zd\n", __func__, len); - return len; + return 0; } static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status) diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 07b5a487d0c8..757ca45b39b8 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -139,14 +139,14 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) } /** - * tpm_ibmvtpm_send - Send tpm request - * + * tpm_ibmvtpm_send() - Send a TPM command * @chip: tpm chip struct * @buf: buffer contains data to send * @count: size of buffer * * Return: - * Number of bytes sent or < 0 on error. + * 0 on success, + * -errno on error */ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { @@ -192,7 +192,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) rc = 0; ibmvtpm->tpm_processing_cmd = false; } else - rc = count; + rc = 0; spin_unlock(&ibmvtpm->rtce_lock); return rc; diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index d8f10047fbba..97f6d4fe0aee 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -354,7 +354,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) for (i = 0; i < count; i++) { wait_and_send(chip, buf[i]); } - return count; + return 0; } static void tpm_inf_cancel(struct tpm_chip *chip) diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 5d6cce74cd3f..9bee3c5eb4bf 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -226,7 +226,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) } outb(NSC_COMMAND_EOC, priv->base + NSC_COMMAND); - return count; + return 0; } static void tpm_nsc_cancel(struct tpm_chip *chip) diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 86dd8521feef..75e7a856177c 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -20,7 +20,8 @@ #include <linux/acpi.h> #include "tpm.h" -#define TPM_PPI_REVISION_ID 1 +#define TPM_PPI_REVISION_ID_1 1 +#define TPM_PPI_REVISION_ID_2 2 #define TPM_PPI_FN_VERSION 1 #define TPM_PPI_FN_SUBREQ 2 #define TPM_PPI_FN_GETREQ 3 @@ -28,7 +29,7 @@ #define TPM_PPI_FN_GETRSP 5 #define TPM_PPI_FN_SUBREQ2 7 #define TPM_PPI_FN_GETOPR 8 -#define PPI_TPM_REQ_MAX 22 +#define PPI_TPM_REQ_MAX 101 /* PPI 1.3 for TPM 2 */ #define PPI_VS_REQ_START 128 #define PPI_VS_REQ_END 255 @@ -36,14 +37,18 @@ static const guid_t tpm_ppi_guid = GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4, 0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53); +static bool tpm_ppi_req_has_parameter(u64 req) +{ + return req == 23; +} + static inline union acpi_object * tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type, - union acpi_object *argv4) + union acpi_object *argv4, u64 rev) { BUG_ON(!ppi_handle); return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid, - TPM_PPI_REVISION_ID, - func, argv4, type); + rev, func, argv4, type); } static ssize_t tpm_show_ppi_version(struct device *dev, @@ -60,9 +65,14 @@ static ssize_t tpm_show_ppi_request(struct device *dev, ssize_t size = -EINVAL; union acpi_object *obj; struct tpm_chip *chip = to_tpm_chip(dev); + u64 rev = TPM_PPI_REVISION_ID_2; + u64 req; + + if (strcmp(chip->ppi_version, "1.2") < 0) + rev = TPM_PPI_REVISION_ID_1; obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, - ACPI_TYPE_PACKAGE, NULL); + ACPI_TYPE_PACKAGE, NULL, rev); if (!obj) return -ENXIO; @@ -72,7 +82,23 @@ static ssize_t tpm_show_ppi_request(struct device *dev, * error. The second is pending TPM operation requested by the OS, 0 * means none and >0 means operation value. */ - if (obj->package.count == 2 && + if (obj->package.count == 3 && + obj->package.elements[0].type == ACPI_TYPE_INTEGER && + obj->package.elements[1].type == ACPI_TYPE_INTEGER && + obj->package.elements[2].type == ACPI_TYPE_INTEGER) { + if (obj->package.elements[0].integer.value) + size = -EFAULT; + else { + req = obj->package.elements[1].integer.value; + if (tpm_ppi_req_has_parameter(req)) + size = scnprintf(buf, PAGE_SIZE, + "%llu %llu\n", req, + obj->package.elements[2].integer.value); + else + size = scnprintf(buf, PAGE_SIZE, + "%llu\n", req); + } + } else if (obj->package.count == 2 && obj->package.elements[0].type == ACPI_TYPE_INTEGER && obj->package.elements[1].type == ACPI_TYPE_INTEGER) { if (obj->package.elements[0].integer.value) @@ -94,9 +120,10 @@ static ssize_t tpm_store_ppi_request(struct device *dev, u32 req; u64 ret; int func = TPM_PPI_FN_SUBREQ; - union acpi_object *obj, tmp; - union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); + union acpi_object *obj, tmp[2]; + union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(2, tmp); struct tpm_chip *chip = to_tpm_chip(dev); + u64 rev = TPM_PPI_REVISION_ID_1; /* * the function to submit TPM operation request to pre-os environment @@ -104,7 +131,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev, * version 1.1 */ if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, - TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2)) + TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_SUBREQ2)) func = TPM_PPI_FN_SUBREQ2; /* @@ -113,20 +140,29 @@ static ssize_t tpm_store_ppi_request(struct device *dev, * string/package type. For PPI version 1.0 and 1.1, use buffer type * for compatibility, and use package type since 1.2 according to spec. */ - if (strcmp(chip->ppi_version, "1.2") < 0) { + if (strcmp(chip->ppi_version, "1.3") == 0) { + if (sscanf(buf, "%llu %llu", &tmp[0].integer.value, + &tmp[1].integer.value) != 2) + goto ppi12; + rev = TPM_PPI_REVISION_ID_2; + tmp[0].type = ACPI_TYPE_INTEGER; + tmp[1].type = ACPI_TYPE_INTEGER; + } else if (strcmp(chip->ppi_version, "1.2") < 0) { if (sscanf(buf, "%d", &req) != 1) return -EINVAL; argv4.type = ACPI_TYPE_BUFFER; argv4.buffer.length = sizeof(req); argv4.buffer.pointer = (u8 *)&req; } else { - tmp.type = ACPI_TYPE_INTEGER; - if (sscanf(buf, "%llu", &tmp.integer.value) != 1) +ppi12: + argv4.package.count = 1; + tmp[0].type = ACPI_TYPE_INTEGER; + if (sscanf(buf, "%llu", &tmp[0].integer.value) != 1) return -EINVAL; } obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, - &argv4); + &argv4, rev); if (!obj) { return -ENXIO; } else { @@ -170,7 +206,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, if (strcmp(chip->ppi_version, "1.2") < 0) obj = &tmp; obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, - ACPI_TYPE_INTEGER, obj); + ACPI_TYPE_INTEGER, obj, TPM_PPI_REVISION_ID_1); if (!obj) { return -ENXIO; } else { @@ -196,7 +232,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev, struct tpm_chip *chip = to_tpm_chip(dev); obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, - ACPI_TYPE_PACKAGE, NULL); + ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1); if (!obj) return -ENXIO; @@ -264,7 +300,7 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, "User not required", }; - if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID, + if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_GETOPR)) return -EPERM; @@ -272,7 +308,8 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, for (i = start; i <= end; i++) { tmp.integer.value = i; obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, - ACPI_TYPE_INTEGER, &argv); + ACPI_TYPE_INTEGER, &argv, + TPM_PPI_REVISION_ID_1); if (!obj) { return -ENOMEM; } else { @@ -338,12 +375,13 @@ void tpm_add_ppi(struct tpm_chip *chip) return; if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, - TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION)) + TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_VERSION)) return; /* Cache PPI version string. */ obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid, - TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, + TPM_PPI_REVISION_ID_1, + TPM_PPI_FN_VERSION, NULL, ACPI_TYPE_STRING); if (obj) { strlcpy(chip->ppi_version, obj->string.pointer, diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index bf7e49cfa643..b9f64684c3fb 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -481,7 +481,7 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len) goto out_err; } } - return len; + return 0; out_err: tpm_tis_ready(chip); return rc; @@ -521,35 +521,38 @@ static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = { (TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } }, }; -static bool tpm_tis_update_timeouts(struct tpm_chip *chip, +static void tpm_tis_update_timeouts(struct tpm_chip *chip, unsigned long *timeout_cap) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int i, rc; u32 did_vid; + chip->timeout_adjusted = false; + if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, true); rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid); - if (rc < 0) + if (rc < 0) { + dev_warn(&chip->dev, "%s: failed to read did_vid: %d\n", + __func__, rc); goto out; + } for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) { if (vendor_timeout_overrides[i].did_vid != did_vid) continue; memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us, sizeof(vendor_timeout_overrides[i].timeout_us)); - rc = true; + chip->timeout_adjusted = true; } - rc = false; - out: if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, false); - return rc; + return; } /* @@ -913,7 +916,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, intmask &= ~TPM_GLOBAL_INT_ENABLE; tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); + rc = tpm_chip_start(chip); + if (rc) + goto out_err; rc = tpm2_probe(chip); + tpm_chip_stop(chip); if (rc) goto out_err; diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 87a0ce47f201..d74f3de74ae6 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -303,9 +303,9 @@ out: static int vtpm_proxy_is_driver_command(struct tpm_chip *chip, u8 *buf, size_t count) { - struct tpm_input_header *hdr = (struct tpm_input_header *)buf; + struct tpm_header *hdr = (struct tpm_header *)buf; - if (count < sizeof(struct tpm_input_header)) + if (count < sizeof(struct tpm_header)) return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -335,7 +335,6 @@ static int vtpm_proxy_is_driver_command(struct tpm_chip *chip, static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count) { struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev); - int rc = 0; if (count > sizeof(proxy_dev->buffer)) { dev_err(&chip->dev, @@ -366,7 +365,7 @@ static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count) wake_up_interruptible(&proxy_dev->wq); - return rc; + return 0; } static void vtpm_proxy_tpm_op_cancel(struct tpm_chip *chip) @@ -402,7 +401,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality) { struct tpm_buf buf; int rc; - const struct tpm_output_header *header; + const struct tpm_header *header; struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev); if (chip->flags & TPM_CHIP_FLAG_TPM2) @@ -417,9 +416,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_NESTED, - "attempting to set locality"); + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality"); proxy_dev->state &= ~STATE_DRIVER_COMMAND; @@ -428,7 +425,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality) goto out; } - header = (const struct tpm_output_header *)buf.data; + header = (const struct tpm_header *)buf.data; rc = be32_to_cpu(header->return_code); if (rc) locality = -1; diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index b150f87f38f5..4e2d00cb0d81 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -163,7 +163,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) wmb(); notify_remote_via_evtchn(priv->evtchn); - ordinal = be32_to_cpu(((struct tpm_input_header*)buf)->ordinal); + ordinal = be32_to_cpu(((struct tpm_header *)buf)->ordinal); duration = tpm_calc_ordinal_duration(chip, ordinal); if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration, @@ -173,7 +173,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) return -ETIME; } - return count; + return 0; } static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) |