diff options
Diffstat (limited to 'drivers/char/tpm/tpm-interface.c')
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 231 |
1 files changed, 98 insertions, 133 deletions
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 1d6729be4cd6..76df4fbcf089 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -30,9 +30,9 @@ #include <linux/spinlock.h> #include <linux/freezer.h> #include <linux/pm_runtime.h> +#include <linux/tpm_eventlog.h> #include "tpm.h" -#include "tpm_eventlog.h" #define TPM_MAX_ORDINAL 243 #define TSC_MAX_ORDINAL 12 @@ -328,7 +328,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -static bool tpm_validate_command(struct tpm_chip *chip, +static int tpm_validate_command(struct tpm_chip *chip, struct tpm_space *space, const u8 *cmd, size_t len) @@ -340,10 +340,10 @@ static bool tpm_validate_command(struct tpm_chip *chip, unsigned int nr_handles; if (len < TPM_HEADER_SIZE) - return false; + return -EINVAL; if (!space) - return true; + return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) { cc = be32_to_cpu(header->ordinal); @@ -352,7 +352,7 @@ static bool tpm_validate_command(struct tpm_chip *chip, if (i < 0) { dev_dbg(&chip->dev, "0x%04X is an invalid command\n", cc); - return false; + return -EOPNOTSUPP; } attrs = chip->cc_attrs_tbl[i]; @@ -362,11 +362,11 @@ static bool tpm_validate_command(struct tpm_chip *chip, goto err_len; } - return true; + return 0; err_len: dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__, len); - return false; + return -EINVAL; } /** @@ -391,8 +391,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, unsigned long stop; bool need_locality; - if (!tpm_validate_command(chip, space, buf, bufsiz)) - return -EINVAL; + rc = tpm_validate_command(chip, space, buf, bufsiz); + if (rc == -EINVAL) + return rc; + /* + * If the command is not implemented by the TPM, synthesize a + * response with a TPM2_RC_COMMAND_CODE return for user-space. + */ + if (rc == -EOPNOTSUPP) { + header->length = cpu_to_be32(sizeof(*header)); + header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); + header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | + TSS2_RESMGR_TPM_RC_LAYER); + return bufsiz; + } if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; @@ -413,6 +425,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, if (chip->dev.parent) pm_runtime_get_sync(chip->dev.parent); + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; @@ -489,6 +504,9 @@ out: chip->locality = -1; } out_no_locality: + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + if (chip->dev.parent) pm_runtime_put_sync(chip->dev.parent); @@ -809,19 +827,20 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) } /** - * tpm_is_tpm2 - is the chip a TPM2 chip? - * @chip_num: tpm idx # or ANY + * tpm_is_tpm2 - do we a have a TPM2 chip? + * @chip: a &struct tpm_chip instance, %NULL for the default chip * - * Returns < 0 on error, and 1 or 0 on success depending whether the chip - * is a TPM2 chip. + * Return: + * 1 if we have a TPM2 chip. + * 0 if we don't have a TPM2 chip. + * A negative number for system errors (errno). */ -int tpm_is_tpm2(u32 chip_num) +int tpm_is_tpm2(struct tpm_chip *chip) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; @@ -833,23 +852,19 @@ int tpm_is_tpm2(u32 chip_num) EXPORT_SYMBOL_GPL(tpm_is_tpm2); /** - * tpm_pcr_read - read a pcr value - * @chip_num: tpm idx # or ANY - * @pcr_idx: pcr idx to retrieve - * @res_buf: TPM_PCR value - * size of res_buf is 20 bytes (or NULL if you don't care) + * tpm_pcr_read - read a PCR value from SHA1 bank + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @pcr_idx: the PCR to be retrieved + * @res_buf: the value of the PCR * - * The TPM driver should be built-in, but for whatever reason it - * isn't, protect against the chip disappearing, by incrementing - * the module usage count. + * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) +int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_pcr_read(chip, pcr_idx, res_buf); @@ -889,25 +904,26 @@ static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash, } /** - * tpm_pcr_extend - extend pcr value with hash - * @chip_num: tpm idx # or AN& - * @pcr_idx: pcr idx to extend - * @hash: hash value used to extend pcr value + * tpm_pcr_extend - extend a PCR value in SHA1 bank. + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @pcr_idx: the PCR to be retrieved + * @hash: the hash value used to extend the PCR value * - * The TPM driver should be built-in, but for whatever reason it - * isn't, protect against the chip disappearing, by incrementing - * the module usage count. + * Note: with TPM 2.0 extends also those banks with a known digest size to the + * cryto subsystem in order to prevent malicious use of those PCR banks. In the + * future we should dynamically determine digest sizes. + * + * Return: same as with tpm_transmit_cmd() */ -int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) +int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) { int rc; - struct tpm_chip *chip; struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)]; u32 count = 0; int i; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -1019,82 +1035,29 @@ out: return rc; } -int tpm_send(u32 chip_num, void *cmd, size_t buflen) +/** + * tpm_send - send a TPM command + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @cmd: a TPM command buffer + * @buflen: the length of the TPM command buffer + * + * Return: same as with tpm_transmit_cmd() + */ +int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0, - "attempting tpm_cmd"); + "attempting to a send a command"); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_send); -static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, - bool check_cancel, bool *canceled) -{ - u8 status = chip->ops->status(chip); - - *canceled = false; - if ((status & mask) == mask) - return true; - if (check_cancel && chip->ops->req_canceled(chip, status)) { - *canceled = true; - return true; - } - return false; -} - -int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue, bool check_cancel) -{ - unsigned long stop; - long rc; - u8 status; - bool canceled = false; - - /* check current status */ - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - - stop = jiffies + timeout; - - if (chip->flags & TPM_CHIP_FLAG_IRQ) { -again: - timeout = stop - jiffies; - if ((long)timeout <= 0) - return -ETIME; - rc = wait_event_interruptible_timeout(*queue, - wait_for_tpm_stat_cond(chip, mask, check_cancel, - &canceled), - timeout); - if (rc > 0) { - if (canceled) - return -ECANCELED; - return 0; - } - if (rc == -ERESTARTSYS && freezing(current)) { - clear_thread_flag(TIF_SIGPENDING); - goto again; - } - } else { - do { - tpm_msleep(TPM_TIMEOUT); - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - } while (time_before(jiffies, stop)); - } - return -ETIME; -} -EXPORT_SYMBOL_GPL(wait_for_tpm_stat); - #define TPM_ORD_SAVESTATE 152 #define SAVESTATE_RESULT_SIZE 10 @@ -1187,16 +1150,15 @@ static const struct tpm_input_header tpm_getrandom_header = { }; /** - * tpm_get_random() - Get random bytes from the tpm's RNG - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @out: destination buffer for the random bytes - * @max: the max number of bytes to write to @out + * tpm_get_random() - get random bytes from the TPM's RNG + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @out: destination buffer for the random bytes + * @max: the max number of bytes to write to @out * - * Returns < 0 on error and the number of bytes read on success + * Return: same as with tpm_transmit_cmd() */ -int tpm_get_random(u32 chip_num, u8 *out, size_t max) +int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) { - struct tpm_chip *chip; struct tpm_cmd_t tpm_cmd; u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength; int err, total = 0, retries = 5; @@ -1205,8 +1167,8 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) return -EINVAL; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL) + chip = tpm_chip_find_get(chip); + if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -1248,22 +1210,23 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) EXPORT_SYMBOL_GPL(tpm_get_random); /** - * tpm_seal_trusted() - seal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options - * @payload: the key data in clear and encrypted form + * tpm_seal_trusted() - seal a trusted key payload + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form * - * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips - * are supported. + * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in + * the keyring subsystem. + * + * Return: same as with tpm_transmit_cmd() */ -int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload, +int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + chip = tpm_chip_find_get(chip); + if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_seal_trusted(chip, payload, options); @@ -1275,21 +1238,23 @@ EXPORT_SYMBOL_GPL(tpm_seal_trusted); /** * tpm_unseal_trusted() - unseal a trusted key - * @chip_num: A specific chip number for the request or TPM_ANY_NUM - * @options: authentication values and other options - * @payload: the key data in clear and encrypted form + * @chip: a &struct tpm_chip instance, %NULL for the default chip + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form + * + * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in + * the keyring subsystem. * - * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips - * are supported. + * Return: same as with tpm_transmit_cmd() */ -int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload, +int tpm_unseal_trusted(struct tpm_chip *chip, + struct trusted_key_payload *payload, struct trusted_key_options *options) { - struct tpm_chip *chip; int rc; - chip = tpm_chip_find_get(chip_num); - if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + chip = tpm_chip_find_get(chip); + if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) return -ENODEV; rc = tpm2_unseal_trusted(chip, payload, options); |