diff options
Diffstat (limited to 'drivers/char/tpm')
24 files changed, 840 insertions, 301 deletions
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 277186d3b668..af985cca413c 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -6,6 +6,7 @@ menuconfig TCG_TPM tristate "TPM Hardware Support" depends on HAS_IOMEM select SECURITYFS + select CRYPTO_HASH_INFO ---help--- If you have a TPM security chip in your system, which implements the Trusted Computing Group's specification, diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index a05b1ebd0b26..3d386a8c579f 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_TCG_TPM) += tpm.o tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ - tpm_eventlog.o + tpm1_eventlog.o tpm2_eventlog.o tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o tpm-$(CONFIG_OF) += tpm_of.o obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 6f060c76217b..e8e0f7c02686 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -18,7 +18,6 @@ #include <linux/module.h> #include <linux/fs.h> -#include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/wait.h> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index a77262d31911..c406343848da 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -141,7 +141,7 @@ static void tpm_dev_release(struct device *dev) * Allocates a new struct tpm_chip instance and assigns a free * device number for it. Must be paired with put_device(&chip->dev). */ -struct tpm_chip *tpm_chip_alloc(struct device *dev, +struct tpm_chip *tpm_chip_alloc(struct device *pdev, const struct tpm_class_ops *ops) { struct tpm_chip *chip; @@ -160,7 +160,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL); mutex_unlock(&idr_lock); if (rc < 0) { - dev_err(dev, "No available tpm device numbers\n"); + dev_err(pdev, "No available tpm device numbers\n"); kfree(chip); return ERR_PTR(rc); } @@ -170,7 +170,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, chip->dev.class = tpm_class; chip->dev.release = tpm_dev_release; - chip->dev.parent = dev; + chip->dev.parent = pdev; chip->dev.groups = chip->groups; if (chip->dev_num == 0) @@ -182,7 +182,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, if (rc) goto out; - if (!dev) + if (!pdev) chip->flags |= TPM_CHIP_FLAG_VIRTUAL; cdev_init(&chip->cdev, &tpm_fops); diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index 912ad30be585..02a8850d3a69 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -38,6 +38,9 @@ static void user_reader_timeout(unsigned long ptr) { struct file_priv *priv = (struct file_priv *)ptr; + pr_warn("TPM user space timeout is deprecated (pid=%d)\n", + task_tgid_nr(current)); + schedule_work(&priv->work); } @@ -157,7 +160,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, mutex_unlock(&priv->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ - mod_timer(&priv->user_read_timer, jiffies + (60 * HZ)); + mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); return in_size; } diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index a2688ac2b48f..bd2128e0b56c 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -47,7 +47,7 @@ static int tpm_suspend_pcr; module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); MODULE_PARM_DESC(suspend_pcr, - "PCR to use for dummy writes to faciltate flush on suspend."); + "PCR to use for dummy writes to facilitate flush on suspend."); /* * Array with one entry per ordinal defining the maximum amount @@ -328,8 +328,17 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -/* - * Internal kernel interface to transmit TPM commands +/** + * tmp_transmit - Internal kernel interface to transmit TPM commands. + * + * @chip: TPM chip to use + * @buf: TPM command buffer + * @bufsiz: length of the TPM command buffer + * @flags: tpm transmit flags - bitmap + * + * Return: + * 0 when the operation is successful. + * A negative number for system errors (errno). */ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, unsigned int flags) @@ -409,31 +418,55 @@ out: return rc; } -#define TPM_DIGEST_SIZE 20 -#define TPM_RET_CODE_IDX 6 - -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, - int len, unsigned int flags, const char *desc) +/** + * tmp_transmit_cmd - send a tpm command to the device + * The function extracts tpm out header return code + * + * @chip: TPM chip to use + * @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 + * + * Return: + * 0 when the operation is successful. + * A negative number for system errors (errno). + * A positive number for a TPM error. + */ +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, + size_t bufsiz, size_t min_rsp_body_length, + unsigned int flags, const char *desc) { const struct tpm_output_header *header; int err; + ssize_t len; - len = tpm_transmit(chip, (const u8 *)cmd, len, flags); + len = tpm_transmit(chip, (const u8 *)buf, bufsiz, flags); if (len < 0) return len; else if (len < TPM_HEADER_SIZE) return -EFAULT; - header = cmd; + header = buf; + if (len != be32_to_cpu(header->length)) + return -EFAULT; err = be32_to_cpu(header->return_code); if (err != 0 && desc) dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + if (err) + return err; + + if (len < min_rsp_body_length + TPM_HEADER_SIZE) + return -EFAULT; - return err; + return 0; } +#define TPM_DIGEST_SIZE 20 +#define TPM_RET_CODE_IDX 6 #define TPM_INTERNAL_RESULT_SIZE 200 #define TPM_ORD_GET_CAP cpu_to_be32(101) #define TPM_ORD_GET_RANDOM cpu_to_be32(70) @@ -445,7 +478,7 @@ static const struct tpm_input_header tpm_getcap_header = { }; ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, - const char *desc) + const char *desc, size_t min_cap_length) { struct tpm_cmd_t tpm_cmd; int rc; @@ -468,8 +501,8 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id); } - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, - desc); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + min_cap_length, 0, desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -493,14 +526,13 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) start_cmd.params.startup_in.startup_type = startup_type; return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0, - "attempting to start the TPM"); + 0, "attempting to start the TPM"); } int tpm_get_timeouts(struct tpm_chip *chip) { cap_t cap; - unsigned long new_timeout[4]; - unsigned long old_timeout[4]; + unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4]; ssize_t rc; if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) @@ -523,8 +555,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) return 0; } - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, - "attempting to determine the timeouts"); + rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL, + sizeof(cap.timeout)); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ @@ -533,16 +565,26 @@ int tpm_get_timeouts(struct tpm_chip *chip) return rc; rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, - "attempting to determine the timeouts"); + "attempting to determine the timeouts", + sizeof(cap.timeout)); } - if (rc) + + if (rc) { + dev_err(&chip->dev, + "A TPM error (%zd) occurred attempting to determine the timeouts\n", + rc); return rc; + } - old_timeout[0] = be32_to_cpu(cap.timeout.a); - old_timeout[1] = be32_to_cpu(cap.timeout.b); - old_timeout[2] = be32_to_cpu(cap.timeout.c); - old_timeout[3] = be32_to_cpu(cap.timeout.d); - memcpy(new_timeout, old_timeout, sizeof(new_timeout)); + timeout_old[0] = jiffies_to_usecs(chip->timeout_a); + timeout_old[1] = jiffies_to_usecs(chip->timeout_b); + timeout_old[2] = jiffies_to_usecs(chip->timeout_c); + timeout_old[3] = jiffies_to_usecs(chip->timeout_d); + timeout_chip[0] = be32_to_cpu(cap.timeout.a); + timeout_chip[1] = be32_to_cpu(cap.timeout.b); + timeout_chip[2] = be32_to_cpu(cap.timeout.c); + timeout_chip[3] = be32_to_cpu(cap.timeout.d); + memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff)); /* * Provide ability for vendor overrides of timeout values in case @@ -550,16 +592,24 @@ int tpm_get_timeouts(struct tpm_chip *chip) */ if (chip->ops->update_timeouts != NULL) chip->timeout_adjusted = - chip->ops->update_timeouts(chip, new_timeout); + chip->ops->update_timeouts(chip, timeout_eff); if (!chip->timeout_adjusted) { - /* Don't overwrite default if value is 0 */ - if (new_timeout[0] != 0 && new_timeout[0] < 1000) { - int i; + /* Restore default if chip reported 0 */ + int i; + for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) { + if (timeout_eff[i]) + continue; + + timeout_eff[i] = timeout_old[i]; + chip->timeout_adjusted = true; + } + + if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) { /* timeouts in msec rather usec */ - for (i = 0; i != ARRAY_SIZE(new_timeout); i++) - new_timeout[i] *= 1000; + for (i = 0; i != ARRAY_SIZE(timeout_eff); i++) + timeout_eff[i] *= 1000; chip->timeout_adjusted = true; } } @@ -568,19 +618,20 @@ int tpm_get_timeouts(struct tpm_chip *chip) if (chip->timeout_adjusted) { dev_info(&chip->dev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", - old_timeout[0], new_timeout[0], - old_timeout[1], new_timeout[1], - old_timeout[2], new_timeout[2], - old_timeout[3], new_timeout[3]); + timeout_chip[0], timeout_eff[0], + timeout_chip[1], timeout_eff[1], + timeout_chip[2], timeout_eff[2], + timeout_chip[3], timeout_eff[3]); } - chip->timeout_a = usecs_to_jiffies(new_timeout[0]); - chip->timeout_b = usecs_to_jiffies(new_timeout[1]); - chip->timeout_c = usecs_to_jiffies(new_timeout[2]); - chip->timeout_d = usecs_to_jiffies(new_timeout[3]); + chip->timeout_a = usecs_to_jiffies(timeout_eff[0]); + chip->timeout_b = usecs_to_jiffies(timeout_eff[1]); + chip->timeout_c = usecs_to_jiffies(timeout_eff[2]); + chip->timeout_d = usecs_to_jiffies(timeout_eff[3]); rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, - "attempting to determine the durations"); + "attempting to determine the durations", + sizeof(cap.duration)); if (rc) return rc; @@ -631,13 +682,14 @@ static int tpm_continue_selftest(struct tpm_chip *chip) struct tpm_cmd_t cmd; cmd.header.in = continue_selftest_header; - rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, 0, "continue selftest"); return rc; } #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 +#define READ_PCR_RESULT_BODY_SIZE 20 static const struct tpm_input_header pcrread_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(14), @@ -651,7 +703,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + READ_PCR_RESULT_BODY_SIZE, 0, "attempting to read a pcr value"); if (rc == 0) @@ -714,6 +767,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) #define EXTEND_PCR_RESULT_SIZE 34 +#define EXTEND_PCR_RESULT_BODY_SIZE 20 static const struct tpm_input_header pcrextend_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(34), @@ -735,13 +789,25 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) struct tpm_cmd_t cmd; 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) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc = tpm2_pcr_extend(chip, pcr_idx, hash); + 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++; + } + + rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list); tpm_put_ops(chip); return rc; } @@ -749,7 +815,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + EXTEND_PCR_RESULT_BODY_SIZE, 0, "attempting extend a PCR value"); tpm_put_ops(chip); @@ -853,7 +920,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) if (chip == NULL) return -ENODEV; - rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd"); + rc = tpm_transmit_cmd(chip, cmd, buflen, 0, 0, "attempting tpm_cmd"); tpm_put_ops(chip); return rc; @@ -955,7 +1022,8 @@ int tpm_pm_suspend(struct device *dev) cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + EXTEND_PCR_RESULT_BODY_SIZE, 0, "extending dummy pcr before suspend"); } @@ -963,7 +1031,7 @@ int tpm_pm_suspend(struct device *dev) for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0, - NULL); + 0, NULL); /* * If the TPM indicates that it is too busy to respond to @@ -1025,7 +1093,7 @@ int tpm_get_random(u32 chip_num, 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); + u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength; int err, total = 0, retries = 5; u8 *dest = out; @@ -1048,11 +1116,20 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) err = tpm_transmit_cmd(chip, &tpm_cmd, TPM_GETRANDOM_RESULT_SIZE + num_bytes, + offsetof(struct tpm_getrandom_out, + rng_data), 0, "attempting get random"); if (err) break; recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); + + rlength = be32_to_cpu(tpm_cmd.header.out.length); + if (rlength < offsetof(struct tpm_getrandom_out, rng_data) + + recd) { + total = -EFAULT; + break; + } memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); dest += recd; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 848ad6580b46..2f596d74f80c 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -21,6 +21,7 @@ #include "tpm.h" #define READ_PUBEK_RESULT_SIZE 314 +#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256) #define TPM_ORD_READPUBEK cpu_to_be32(124) static const struct tpm_input_header tpm_readpubek_header = { .tag = TPM_TAG_RQU_COMMAND, @@ -39,7 +40,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = to_tpm_chip(dev); tpm_cmd.header.in = tpm_readpubek_header; - err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0, + err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, + READ_PUBEK_RESULT_MIN_BODY_SIZE, 0, "attempting to read the PUBEK"); if (err) goto out; @@ -95,7 +97,8 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = to_tpm_chip(dev); rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap, - "attempting to determine the number of PCRS"); + "attempting to determine the number of PCRS", + sizeof(cap.num_pcrs)); if (rc) return 0; @@ -120,7 +123,8 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, - "attempting to determine the permanent enabled state"); + "attempting to determine the permanent enabled state", + sizeof(cap.perm_flags)); if (rc) return 0; @@ -136,7 +140,8 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, - "attempting to determine the permanent active state"); + "attempting to determine the permanent active state", + sizeof(cap.perm_flags)); if (rc) return 0; @@ -152,7 +157,8 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, - "attempting to determine the owner state"); + "attempting to determine the owner state", + sizeof(cap.owned)); if (rc) return 0; @@ -168,7 +174,8 @@ static ssize_t temp_deactivated_show(struct device *dev, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, - "attempting to determine the temporary state"); + "attempting to determine the temporary state", + sizeof(cap.stclear_flags)); if (rc) return 0; @@ -186,7 +193,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, char *str = buf; rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, - "attempting to determine the manufacturer"); + "attempting to determine the manufacturer", + sizeof(cap.manufacturer_id)); if (rc) return 0; str += sprintf(str, "Manufacturer: 0x%x\n", @@ -194,7 +202,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap, - "attempting to determine the 1.2 version"); + "attempting to determine the 1.2 version", + sizeof(cap.tpm_version_1_2)); if (!rc) { str += sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", @@ -205,7 +214,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, } else { /* Otherwise just use TPM_STRUCT_VER */ rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap, - "attempting to determine the 1.1 version"); + "attempting to determine the 1.1 version", + sizeof(cap.tpm_version)); if (rc) return 0; str += sprintf(str, diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 1ae976894257..4937b56a275c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -34,8 +34,7 @@ #include <linux/acpi.h> #include <linux/cdev.h> #include <linux/highmem.h> - -#include "tpm_eventlog.h" +#include <crypto/hash_info.h> enum tpm_const { TPM_MINOR = 224, /* officially assigned */ @@ -97,6 +96,7 @@ enum tpm2_return_codes { }; enum tpm2_algorithms { + TPM2_ALG_ERROR = 0x0000, TPM2_ALG_SHA1 = 0x0004, TPM2_ALG_KEYEDHASH = 0x0008, TPM2_ALG_SHA256 = 0x000B, @@ -127,6 +127,7 @@ enum tpm2_permanent_handles { }; enum tpm2_capabilities { + TPM2_CAP_PCRS = 5, TPM2_CAP_TPM_PROPERTIES = 6, }; @@ -148,6 +149,11 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), }; +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; @@ -187,6 +193,8 @@ struct tpm_chip { 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]; @@ -195,17 +203,6 @@ struct tpm_chip { #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) -static inline int tpm_read_index(int base, int index) -{ - outb(index, base); - return inb(base+1) & 0xFF; -} - -static inline void tpm_write_index(int base, int index, int value) -{ - outb(index, base); - outb(value & 0xFF, base+1); -} struct tpm_input_header { __be16 tag; __be32 length; @@ -284,7 +281,7 @@ struct permanent_flags_t { typedef union { struct permanent_flags_t perm_flags; struct stclear_flags_t stclear_flags; - bool owned; + __u8 owned; __be32 num_pcrs; struct tpm_version_t tpm_version; struct tpm_version_1_2_t tpm_version_1_2; @@ -387,6 +384,11 @@ struct tpm_cmd_t { tpm_cmd_params params; } __packed; +struct tpm2_digest { + u16 alg_id; + u8 digest[SHA512_DIGEST_SIZE]; +} __packed; + /* A string buffer type for constructing TPM commands. This is based on the * ideas of string buffer code in security/keys/trusted.h but is heap based * in order to keep the stack usage minimal. @@ -493,10 +495,11 @@ enum tpm_transmit_flags { ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, unsigned int flags); -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, - unsigned int flags, const char *desc); +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, size_t bufsiz, + size_t min_rsp_body_len, unsigned int flags, + const char *desc); ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, - const char *desc); + const char *desc, size_t min_cap_length); int tpm_get_timeouts(struct tpm_chip *); int tpm1_auto_startup(struct tpm_chip *chip); int tpm_do_selftest(struct tpm_chip *chip); @@ -529,8 +532,14 @@ static inline void tpm_add_ppi(struct tpm_chip *chip) } #endif +static inline inline u32 tpm2_rc_value(u32 rc) +{ + return (rc & BIT(7)) ? rc & 0xff : rc; +} + int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); -int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, + struct tpm2_digest *digests); int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); int tpm2_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c index 11bb1138a828..9a8605e500b5 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm1_eventlog.c @@ -390,9 +390,6 @@ int tpm_bios_log_setup(struct tpm_chip *chip) unsigned int cnt; int rc = 0; - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return 0; - rc = tpm_read_log(chip); if (rc) return rc; @@ -407,7 +404,13 @@ int tpm_bios_log_setup(struct tpm_chip *chip) cnt++; chip->bin_log_seqops.chip = chip; - chip->bin_log_seqops.seqops = &tpm_binary_b_measurements_seqops; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + chip->bin_log_seqops.seqops = + &tpm2_binary_b_measurements_seqops; + else + chip->bin_log_seqops.seqops = + &tpm_binary_b_measurements_seqops; + chip->bios_dir[cnt] = securityfs_create_file("binary_bios_measurements", @@ -418,17 +421,21 @@ int tpm_bios_log_setup(struct tpm_chip *chip) goto err; cnt++; - chip->ascii_log_seqops.chip = chip; - chip->ascii_log_seqops.seqops = &tpm_ascii_b_measurements_seqops; + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { - chip->bios_dir[cnt] = - securityfs_create_file("ascii_bios_measurements", - 0440, chip->bios_dir[0], - (void *)&chip->ascii_log_seqops, - &tpm_bios_measurements_ops); - if (IS_ERR(chip->bios_dir[cnt])) - goto err; - cnt++; + chip->ascii_log_seqops.chip = chip; + chip->ascii_log_seqops.seqops = + &tpm_ascii_b_measurements_seqops; + + chip->bios_dir[cnt] = + securityfs_create_file("ascii_bios_measurements", + 0440, chip->bios_dir[0], + (void *)&chip->ascii_log_seqops, + &tpm_bios_measurements_ops); + if (IS_ERR(chip->bios_dir[cnt])) + goto err; + cnt++; + } return 0; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index da5b782a9731..881aea9732bf 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -53,22 +53,6 @@ struct tpm2_pcr_read_out { u8 digest[TPM_DIGEST_SIZE]; } __packed; -struct tpm2_null_auth_area { - __be32 handle; - __be16 nonce_size; - u8 attributes; - __be16 auth_size; -} __packed; - -struct tpm2_pcr_extend_in { - __be32 pcr_idx; - __be32 auth_area_size; - struct tpm2_null_auth_area auth_area; - __be32 digest_cnt; - __be16 hash_alg; - u8 digest[TPM_DIGEST_SIZE]; -} __packed; - struct tpm2_get_tpm_pt_in { __be32 cap_id; __be32 property_id; @@ -97,7 +81,6 @@ union tpm2_cmd_params { struct tpm2_self_test_in selftest_in; struct tpm2_pcr_read_in pcrread_in; struct tpm2_pcr_read_out pcrread_out; - struct tpm2_pcr_extend_in pcrextend_in; struct tpm2_get_tpm_pt_in get_tpm_pt_in; struct tpm2_get_tpm_pt_out get_tpm_pt_out; struct tpm2_get_random_in getrandom_in; @@ -248,6 +231,9 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_pcr_read_in)) +#define TPM2_PCR_READ_RESP_BODY_SIZE \ + sizeof(struct tpm2_pcr_read_out) + static const struct tpm_input_header tpm2_pcrread_header = { .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), @@ -258,11 +244,9 @@ static const struct tpm_input_header tpm2_pcrread_header = { * tpm2_pcr_read() - read a PCR value * @chip: TPM chip to use. * @pcr_idx: index of the PCR to read. - * @ref_buf: buffer to store the resulting hash, + * @res_buf: buffer to store the resulting hash. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { @@ -282,8 +266,9 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) sizeof(cmd.params.pcrread_in.pcr_select)); cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, - "attempting to read a pcr value"); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + TPM2_PCR_READ_RESP_BODY_SIZE, + 0, "attempting to read a pcr value"); if (rc == 0) { buf = cmd.params.pcrread_out.digest; memcpy(res_buf, buf, TPM_DIGEST_SIZE); @@ -292,50 +277,71 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) return rc; } -#define TPM2_GET_PCREXTEND_IN_SIZE \ - (sizeof(struct tpm_input_header) + \ - sizeof(struct tpm2_pcr_extend_in)) - -static const struct tpm_input_header tpm2_pcrextend_header = { - .tag = cpu_to_be16(TPM2_ST_SESSIONS), - .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE), - .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND) -}; +struct tpm2_null_auth_area { + __be32 handle; + __be16 nonce_size; + u8 attributes; + __be16 auth_size; +} __packed; /** * tpm2_pcr_extend() - extend a PCR value + * * @chip: TPM chip to use. * @pcr_idx: index of the PCR. - * @hash: hash value to use for the extend operation. + * @count: number of digests passed. + * @digests: list of pcr banks and corresponding digest values to extend. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ -int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, + struct tpm2_digest *digests) { - struct tpm2_cmd cmd; + 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) + return rc; + + tpm_buf_append_u32(&buf, pcr_idx); + + auth_area.handle = cpu_to_be32(TPM2_RS_PW); + auth_area.nonce_size = 0; + auth_area.attributes = 0; + auth_area.auth_size = 0; + + 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]); + } + } - cmd.header.in = tpm2_pcrextend_header; - cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); - cmd.params.pcrextend_in.auth_area_size = - cpu_to_be32(sizeof(struct tpm2_null_auth_area)); - cmd.params.pcrextend_in.auth_area.handle = - cpu_to_be32(TPM2_RS_PW); - cmd.params.pcrextend_in.auth_area.nonce_size = 0; - cmd.params.pcrextend_in.auth_area.attributes = 0; - cmd.params.pcrextend_in.auth_area.auth_size = 0; - cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1); - cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); - memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE); - - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, 0, "attempting extend a PCR value"); + tpm_buf_destroy(&buf); + return rc; } + #define TPM2_GETRANDOM_IN_SIZE \ (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_get_random_in)) @@ -348,18 +354,18 @@ static const struct tpm_input_header tpm2_getrandom_header = { /** * tpm2_get_random() - get random bytes from the TPM RNG + * * @chip: TPM chip to use * @out: destination buffer for the random bytes * @max: the max number of bytes to write to @out * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: + * Size of the output buffer, or -EIO on error. */ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) { struct tpm2_cmd cmd; - u32 recd; + u32 recd, rlength; u32 num_bytes; int err; int total = 0; @@ -376,13 +382,19 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) cmd.header.in = tpm2_getrandom_header; cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); - err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, - "attempting get random"); + err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + offsetof(struct tpm2_get_random_out, + buffer), + 0, "attempting get random"); if (err) break; recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size), num_bytes); + rlength = be32_to_cpu(cmd.header.out.length); + if (rlength < offsetof(struct tpm2_get_random_out, buffer) + + recd) + return -EFAULT; memcpy(dest, cmd.params.getrandom_out.buffer, recd); dest += recd; @@ -397,6 +409,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_get_tpm_pt_in)) +#define TPM2_GET_TPM_PT_OUT_BODY_SIZE \ + sizeof(struct tpm2_get_tpm_pt_out) + static const struct tpm_input_header tpm2_get_tpm_pt_header = { .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE), @@ -404,15 +419,15 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = { }; /** - * Append TPMS_AUTH_COMMAND to the buffer. The buffer must be allocated with - * tpm_buf_alloc(). - * - * @param buf: an allocated tpm_buf instance - * @param nonce: the session nonce, may be NULL if not used - * @param nonce_len: the session nonce length, may be 0 if not used - * @param attributes: the session attributes - * @param hmac: the session HMAC or password, may be NULL if not used - * @param hmac_len: the session HMAC or password length, maybe 0 if not used + * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. + * + * @buf: an allocated tpm_buf instance + * @session_handle: session handle + * @nonce: the session nonce, may be NULL if not used + * @nonce_len: the session nonce length, may be 0 if not used + * @attributes: the session attributes + * @hmac: the session HMAC or password, may be NULL if not used + * @hmac_len: the session HMAC or password length, maybe 0 if not used */ static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle, const u8 *nonce, u16 nonce_len, @@ -435,7 +450,8 @@ static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle, /** * tpm2_seal_trusted() - seal the payload of a trusted key - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @payload: the key data in clear and encrypted form * @options: authentication values and other options * @@ -447,7 +463,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, { unsigned int blob_len; struct tpm_buf buf; - u32 hash; + u32 hash, rlength; int i; int rc; @@ -512,7 +528,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, "sealing data"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, 0, + "sealing data"); if (rc) goto out; @@ -521,6 +538,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip, rc = -E2BIG; goto out; } + rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)->header.out.length); + if (rlength < TPM_HEADER_SIZE + 4 + blob_len) { + rc = -EFAULT; + goto out; + } memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len); payload->blob_len = blob_len; @@ -529,7 +551,7 @@ out: tpm_buf_destroy(&buf); if (rc > 0) { - if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH) + if (tpm2_rc_value(rc) == TPM2_RC_HASH) rc = -EINVAL; else rc = -EPERM; @@ -540,11 +562,17 @@ out: /** * tpm2_load_cmd() - execute a TPM2_Load command - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @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: same as with tpm_transmit_cmd + * Return: 0 on success. + * -E2BIG on wrong payload size. + * -EPERM on tpm error status. + * < 0 error from tpm_transmit_cmd. */ static int tpm2_load_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -584,7 +612,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "loading blob"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, flags, + "loading blob"); if (!rc) *blob_handle = be32_to_cpup( (__be32 *) &buf.data[TPM_HEADER_SIZE]); @@ -600,11 +629,12 @@ out: /** * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command - * @chip_num: TPM chip to use - * @payload: the key data in clear and encrypted form - * @options: authentication values and other options * - * Return: same as with tpm_transmit_cmd + * @chip: TPM chip to use + * @handle: the key data in clear and encrypted form + * @flags: tpm transmit flags + * + * Return: Same as with tpm_transmit_cmd. */ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, unsigned int flags) @@ -621,7 +651,7 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, tpm_buf_append_u32(&buf, handle); - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags, "flushing context"); if (rc) dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle, @@ -632,11 +662,16 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, /** * tpm2_unseal_cmd() - execute a TPM2_Unload command - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @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: same as with tpm_transmit_cmd + * Return: 0 on success + * -EPERM on tpm error status + * < 0 error from tpm_transmit_cmd */ static int tpm2_unseal_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -647,6 +682,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, u16 data_len; u8 *data; int rc; + u32 rlength; rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); if (rc) @@ -661,13 +697,21 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, options->blobauth /* hmac */, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "unsealing"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 6, flags, + "unsealing"); if (rc > 0) rc = -EPERM; if (!rc) { data_len = be16_to_cpup( (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); + + rlength = be32_to_cpu(((struct tpm2_cmd *)&buf) + ->header.out.length); + if (rlength < TPM_HEADER_SIZE + 6 + data_len) { + rc = -EFAULT; + goto out; + } data = &buf.data[TPM_HEADER_SIZE + 6]; memcpy(payload->key, data, data_len - 1); @@ -675,17 +719,19 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, payload->migratable = data[data_len - 1]; } +out: tpm_buf_destroy(&buf); return rc; } /** * tpm2_unseal_trusted() - unseal the payload of a trusted key - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @payload: the key data in clear and encrypted form * @options: authentication values and other options * - * Return: < 0 on error and 0 on success. + * Return: Same as with tpm_transmit_cmd. */ int tpm2_unseal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -715,9 +761,7 @@ out: * @value: output variable. * @desc: passed to tpm_transmit_cmd() * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, const char *desc) @@ -730,7 +774,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, desc); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc); if (!rc) *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value); @@ -750,13 +795,12 @@ static const struct tpm_input_header tpm2_startup_header = { /** * tpm2_startup() - send startup command to the TPM chip + * * @chip: TPM chip to use. - * @startup_type startup type. The value is either + * @startup_type: startup type. The value is either * TPM_SU_CLEAR or TPM_SU_STATE. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) { @@ -765,7 +809,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) cmd.header.in = tpm2_startup_header; cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); - return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, "attempting to start the TPM"); } @@ -781,8 +825,9 @@ static const struct tpm_input_header tpm2_shutdown_header = { /** * tpm2_shutdown() - send shutdown command to the TPM chip + * * @chip: TPM chip to use. - * @shutdown_type shutdown type. The value is either + * @shutdown_type: shutdown type. The value is either * TPM_SU_CLEAR or TPM_SU_STATE. */ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) @@ -793,7 +838,8 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) cmd.header.in = tpm2_shutdown_header; cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "stopping the TPM"); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, + "stopping the TPM"); /* In places where shutdown command is sent there's no much we can do * except print the error code on a system failure. @@ -805,12 +851,11 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) /* * tpm2_calc_ordinal_duration() - maximum duration for a command + * * @chip: TPM chip to use. * @ordinal: command code number. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: maximum duration for a command */ unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) { @@ -842,13 +887,12 @@ static const struct tpm_input_header tpm2_selftest_header = { /** * tpm2_continue_selftest() - start a self test + * * @chip: TPM chip to use * @full: test all commands instead of testing only those that were not * previously tested. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd with exception of RC_TESTING. */ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) { @@ -858,7 +902,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) cmd.header.in = tpm2_selftest_header; cmd.params.selftest_in.full_test = full; - rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0, "continue selftest"); /* At least some prototype chips seem to give RC_TESTING error @@ -874,14 +918,13 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) /** * tpm2_do_selftest() - run a full self test + * * @chip: TPM chip to use * + * Return: Same as with tpm_transmit_cmd. + * * During the self test TPM2 commands return with the error code RC_TESTING. * Waiting is done by issuing PCR read until it executes successfully. - * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. */ static int tpm2_do_selftest(struct tpm_chip *chip) { @@ -910,7 +953,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip) cmd.params.pcrread_in.pcr_select[1] = 0x00; cmd.params.pcrread_in.pcr_select[2] = 0x00; - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL); if (rc < 0) break; @@ -928,6 +971,8 @@ static int tpm2_do_selftest(struct tpm_chip *chip) * tpm2_probe() - probe TPM 2.0 * @chip: TPM chip to use * + * Return: < 0 error and 0 on success. + * * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on * the reply tag. */ @@ -941,7 +986,7 @@ int tpm2_probe(struct tpm_chip *chip) cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL); if (rc < 0) return rc; @@ -952,12 +997,85 @@ int tpm2_probe(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm2_probe); +struct tpm2_pcr_selection { + __be16 hash_alg; + u8 size_of_select; + u8 pcr_select[3]; +} __packed; + +static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) +{ + struct tpm2_pcr_selection pcr_selection; + struct tpm_buf buf; + void *marker; + void *end; + void *pcr_select_offset; + unsigned int count; + u32 sizeof_pcr_selection; + u32 rsp_len; + int rc; + int i = 0; + + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); + if (rc) + return rc; + + tpm_buf_append_u32(&buf, TPM2_CAP_PCRS); + tpm_buf_append_u32(&buf, 0); + tpm_buf_append_u32(&buf, 1); + + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9, 0, + "get tpm pcr allocation"); + if (rc) + goto out; + + count = be32_to_cpup( + (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); + + if (count > ARRAY_SIZE(chip->active_banks)) { + rc = -ENODEV; + goto out; + } + + marker = &buf.data[TPM_HEADER_SIZE + 9]; + + rsp_len = be32_to_cpup((__be32 *)&buf.data[2]); + end = &buf.data[rsp_len]; + + for (i = 0; i < count; i++) { + pcr_select_offset = marker + + offsetof(struct tpm2_pcr_selection, size_of_select); + if (pcr_select_offset >= end) { + rc = -EFAULT; + break; + } + + memcpy(&pcr_selection, marker, sizeof(pcr_selection)); + chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg); + sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + + sizeof(pcr_selection.size_of_select) + + pcr_selection.size_of_select; + marker = marker + sizeof_pcr_selection; + } + +out: + if (i < ARRAY_SIZE(chip->active_banks)) + chip->active_banks[i] = TPM2_ALG_ERROR; + + tpm_buf_destroy(&buf); + + return rc; +} + /** * tpm2_auto_startup - Perform the standard automatic TPM initialization * sequence * @chip: TPM chip to use * - * Returns 0 on success, < 0 in case of fatal error. + * Initializes timeout values for operation and command durations, conducts + * a self-test and reads the list of active PCR banks. + * + * Return: 0 on success. Otherwise, a system error code is returned. */ int tpm2_auto_startup(struct tpm_chip *chip) { @@ -985,6 +1103,8 @@ int tpm2_auto_startup(struct tpm_chip *chip) } } + rc = tpm2_get_pcr_allocation(chip); + out: if (rc > 0) rc = -ENODEV; diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c new file mode 100644 index 000000000000..513897cf9c4b --- /dev/null +++ b/drivers/char/tpm/tpm2_eventlog.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2016 IBM Corporation + * + * Authors: + * Nayna Jain <nayna@linux.vnet.ibm.com> + * + * Access to TPM 2.0 event log as written by Firmware. + * It assumes that writer of event log has followed TCG Specification + * for Family "2.0" and written the event data in little endian. + * With that, it doesn't need any endian conversion for structure + * content. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/seq_file.h> +#include <linux/fs.h> +#include <linux/security.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "tpm.h" +#include "tpm_eventlog.h" + +/* + * calc_tpm2_event_size() - calculate the event size, where event + * is an entry in the TPM 2.0 event log. The event is of type Crypto + * Agile Log Entry Format as defined in TCG EFI Protocol Specification + * Family "2.0". + + * @event: event whose size is to be calculated. + * @event_header: the first event in the event log. + * + * Returns size of the event. If it is an invalid event, returns 0. + */ +static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, + struct tcg_pcr_event *event_header) +{ + struct tcg_efi_specid_event *efispecid; + struct tcg_event_field *event_field; + void *marker; + void *marker_start; + u32 halg_size; + size_t size; + u16 halg; + int i; + int j; + + marker = event; + marker_start = marker; + marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) + + sizeof(event->count); + + efispecid = (struct tcg_efi_specid_event *)event_header->event; + + for (i = 0; (i < event->count) && (i < TPM2_ACTIVE_PCR_BANKS); + i++) { + halg_size = sizeof(event->digests[i].alg_id); + memcpy(&halg, marker, halg_size); + marker = marker + halg_size; + for (j = 0; (j < efispecid->num_algs); j++) { + if (halg == efispecid->digest_sizes[j].alg_id) { + marker = marker + + efispecid->digest_sizes[j].digest_size; + break; + } + } + } + + event_field = (struct tcg_event_field *)marker; + marker = marker + sizeof(event_field->event_size) + + event_field->event_size; + size = marker - marker_start; + + if ((event->event_type == 0) && (event_field->event_size == 0)) + return 0; + + return size; +} + +static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) +{ + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *addr = log->bios_event_log; + void *limit = log->bios_event_log_end; + struct tcg_pcr_event *event_header; + struct tcg_pcr_event2 *event; + size_t size; + int i; + + event_header = addr; + size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) + + event_header->event_size; + + if (*pos == 0) { + if (addr + size < limit) { + if ((event_header->event_type == 0) && + (event_header->event_size == 0)) + return NULL; + return SEQ_START_TOKEN; + } + } + + if (*pos > 0) { + addr += size; + event = addr; + size = calc_tpm2_event_size(event, event_header); + if ((addr + size >= limit) || (size == 0)) + return NULL; + } + + for (i = 0; i < (*pos - 1); i++) { + event = addr; + size = calc_tpm2_event_size(event, event_header); + + if ((addr + size >= limit) || (size == 0)) + return NULL; + addr += size; + } + + return addr; +} + +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 tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *limit = log->bios_event_log_end; + size_t event_size; + void *marker; + + event_header = log->bios_event_log; + + if (v == SEQ_START_TOKEN) { + event_size = sizeof(struct tcg_pcr_event) - + sizeof(event_header->event) + event_header->event_size; + marker = event_header; + } else { + event = v; + event_size = calc_tpm2_event_size(event, event_header); + if (event_size == 0) + return NULL; + marker = event; + } + + marker = marker + event_size; + if (marker >= limit) + return NULL; + v = marker; + event = v; + + event_size = calc_tpm2_event_size(event, event_header); + if (((v + event_size) >= limit) || (event_size == 0)) + return NULL; + + (*pos)++; + return v; +} + +static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) +{ +} + +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; + void *temp_ptr; + size_t size; + + if (v == SEQ_START_TOKEN) { + size = sizeof(struct tcg_pcr_event) - + sizeof(event_header->event) + event_header->event_size; + + temp_ptr = event_header; + + if (size > 0) + seq_write(m, temp_ptr, size); + } else { + size = calc_tpm2_event_size(event, event_header); + temp_ptr = event; + if (size > 0) + seq_write(m, temp_ptr, size); + } + + return 0; +} + +const struct seq_operations tpm2_binary_b_measurements_seqops = { + .start = tpm2_bios_measurements_start, + .next = tpm2_bios_measurements_next, + .stop = tpm2_bios_measurements_stop, + .show = tpm2_binary_bios_measurements_show, +}; diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index b7718c95fd0b..169edf3ce86d 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -54,6 +54,9 @@ int tpm_read_log_acpi(struct tpm_chip *chip) u64 len, start; struct tpm_bios_log *log; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return -ENODEV; + log = &chip->log; /* Unfortuntely ACPI does not associate the event log with a specific diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h index 4f96d80cdce9..5c82eb47665e 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h @@ -96,6 +96,12 @@ enum tpm_atmel_addr { TPM_ATMEL_BASE_ADDR_HI = 0x09 }; +static inline int tpm_read_index(int base, int index) +{ + outb(index, base); + return inb(base+1) & 0xFF; +} + /* Verify this is a 1.1 Atmel TPM */ static int atmel_verify_tpm11(void) { diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 717b6b47c042..86f355b6df1d 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -264,10 +264,12 @@ static const struct tpm_class_ops tpm_crb = { static int crb_check_resource(struct acpi_resource *ares, void *data) { struct resource *io_res = data; - struct resource res; + struct resource_win win; + struct resource *res = &(win.res); - if (acpi_dev_resource_memory(ares, &res)) { - *io_res = res; + if (acpi_dev_resource_memory(ares, res) || + acpi_dev_resource_address_space(ares, &win)) { + *io_res = *res; io_res->name = NULL; } diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h index 1660d74ea79a..b4b549559203 100644 --- a/drivers/char/tpm/tpm_eventlog.h +++ b/drivers/char/tpm/tpm_eventlog.h @@ -2,9 +2,12 @@ #ifndef __TPM_EVENTLOG_H__ #define __TPM_EVENTLOG_H__ +#include <crypto/hash_info.h> + #define TCG_EVENT_NAME_LEN_MAX 255 #define MAX_TEXT_EVENT 1000 /* Max event string length */ #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ +#define TPM2_ACTIVE_PCR_BANKS 3 #ifdef CONFIG_PPC64 #define do_endian_conversion(x) be32_to_cpu(x) @@ -17,11 +20,6 @@ enum bios_platform_class { BIOS_SERVER = 0x01, }; -struct tpm_bios_log { - void *bios_event_log; - void *bios_event_log_end; -}; - struct tcpa_event { u32 pcr_index; u32 event_type; @@ -73,6 +71,49 @@ enum tcpa_pc_event_ids { HOST_TABLE_OF_DEVICES, }; +/* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */ + +struct tcg_efi_specid_event_algs { + u16 alg_id; + u16 digest_size; +} __packed; + +struct tcg_efi_specid_event { + u8 signature[16]; + u32 platform_class; + u8 spec_version_minor; + u8 spec_version_major; + u8 spec_errata; + u8 uintnsize; + u32 num_algs; + struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS]; + u8 vendor_info_size; + u8 vendor_info[0]; +} __packed; + +struct tcg_pcr_event { + u32 pcr_idx; + u32 event_type; + u8 digest[20]; + u32 event_size; + u8 event[0]; +} __packed; + +struct tcg_event_field { + u32 event_size; + u8 event[0]; +} __packed; + +struct tcg_pcr_event2 { + u32 pcr_idx; + u32 event_type; + u32 count; + struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS]; + struct tcg_event_field event; +} __packed; + +extern const struct seq_operations tpm2_binary_b_measurements_seqops; + #if defined(CONFIG_ACPI) int tpm_read_log_acpi(struct tpm_chip *chip); #else diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 946025a7413b..1b9d61ffe991 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -40,11 +40,12 @@ MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); /** * ibmvtpm_send_crq - Send a CRQ request + * * @vdev: vio device struct * @w1: first word * @w2: second word * - * Return value: + * Return: * 0 -Sucess * Non-zero - Failure */ @@ -55,11 +56,12 @@ static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2) /** * tpm_ibmvtpm_recv - Receive data after send + * * @chip: tpm chip struct * @buf: buffer to read - * count: size of buffer + * @count: size of buffer * - * Return value: + * Return: * Number of bytes read */ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) @@ -96,12 +98,13 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) /** * tpm_ibmvtpm_send - Send tpm request + * * @chip: tpm chip struct * @buf: buffer contains data to send - * count: size of buffer + * @count: size of buffer * - * Return value: - * Number of bytes sent + * Return: + * Number of bytes sent or < 0 on error. */ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { @@ -170,11 +173,12 @@ static u8 tpm_ibmvtpm_status(struct tpm_chip *chip) /** * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size + * * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) { @@ -197,11 +201,12 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) /** * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version * - Note that this is vtpm version and not tpm version + * * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) { @@ -225,9 +230,9 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) { @@ -245,9 +250,9 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) * ibmvtpm_crq_send_init - Send a CRQ initialize message * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) { @@ -265,8 +270,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) * tpm_ibmvtpm_remove - ibm vtpm remove entry point * @vdev: vio device struct * - * Return value: - * 0 + * Return: Always 0. */ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) { @@ -303,18 +307,19 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver * @vdev: vio device struct * - * Return value: - * Number of bytes the driver needs to DMA map + * Return: + * Number of bytes the driver needs to DMA map. */ static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) { struct tpm_chip *chip = dev_get_drvdata(&vdev->dev); struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); - /* ibmvtpm initializes at probe time, so the data we are - * asking for may not be set yet. Estimate that 4K required - * for TCE-mapped buffer in addition to CRQ. - */ + /* + * ibmvtpm initializes at probe time, so the data we are + * asking for may not be set yet. Estimate that 4K required + * for TCE-mapped buffer in addition to CRQ. + */ if (!ibmvtpm) return CRQ_RES_BUF_SIZE + PAGE_SIZE; @@ -325,8 +330,7 @@ static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) * tpm_ibmvtpm_suspend - Suspend * @dev: device struct * - * Return value: - * 0 + * Return: Always 0. */ static int tpm_ibmvtpm_suspend(struct device *dev) { @@ -350,11 +354,12 @@ static int tpm_ibmvtpm_suspend(struct device *dev) /** * ibmvtpm_reset_crq - Reset CRQ + * * @ibmvtpm: ibm vtpm struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) { @@ -376,10 +381,10 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) /** * tpm_ibmvtpm_resume - Resume from suspend + * * @dev: device struct * - * Return value: - * 0 + * Return: Always 0. */ static int tpm_ibmvtpm_resume(struct device *dev) { @@ -434,10 +439,10 @@ static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { /** * ibmvtpm_crq_get_next - Get next responded crq - * @ibmvtpm vtpm device struct * - * Return value: - * vtpm crq pointer + * @ibmvtpm: vtpm device struct + * + * Return: vtpm crq pointer or NULL. */ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) { @@ -455,11 +460,10 @@ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) /** * ibmvtpm_crq_process - Process responded crq - * @crq crq to be processed - * @ibmvtpm vtpm device struct * - * Return value: - * Nothing + * @crq: crq to be processed + * @ibmvtpm: vtpm device struct + * */ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, struct ibmvtpm_dev *ibmvtpm) @@ -528,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, /** * ibmvtpm_interrupt - Interrupt handler + * * @irq: irq number to handle * @vtpm_instance: vtpm that received interrupt * @@ -554,12 +559,13 @@ static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance) /** * tpm_ibmvtpm_probe - ibm vtpm initialize entry point + * * @vio_dev: vio device struct * @id: vio device id struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, const struct vio_device_id *id) @@ -671,11 +677,12 @@ static struct vio_driver ibmvtpm_driver = { }; /** - * ibmvtpm_module_init - Initialize ibm vtpm module + * ibmvtpm_module_init - Initialize ibm vtpm module. * - * Return value: - * 0 -Success - * Non-zero - Failure + * + * Return: + * 0 on success. + * Non-zero on failure. */ static int __init ibmvtpm_module_init(void) { @@ -683,10 +690,7 @@ static int __init ibmvtpm_module_init(void) } /** - * ibmvtpm_module_exit - Teardown ibm vtpm module - * - * Return value: - * Nothing + * ibmvtpm_module_exit - Tear down ibm vtpm module. */ static void __exit ibmvtpm_module_exit(void) { diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 9ff0e072c476..5d6cce74cd3f 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -278,6 +278,18 @@ static struct platform_driver nsc_drv = { }, }; +static inline int tpm_read_index(int base, int index) +{ + outb(index, base); + return inb(base+1) & 0xFF; +} + +static inline void tpm_write_index(int base, int index, int value) +{ + outb(index, base); + outb(value & 0xFF, base+1); +} + static int __init init_nsc(void) { int rc = 0; diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 7dee42d7b5e0..de57d4ac8901 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -27,6 +27,8 @@ int tpm_read_log_of(struct tpm_chip *chip) const u32 *sizep; const u64 *basep; struct tpm_bios_log *log; + u32 size; + u64 base; log = &chip->log; if (chip->dev.parent && chip->dev.parent->of_node) @@ -41,18 +43,35 @@ int tpm_read_log_of(struct tpm_chip *chip) if (sizep == NULL || basep == NULL) return -EIO; - if (*sizep == 0) { + /* + * For both vtpm/tpm, firmware has log addr and log size in big + * endian format. But in case of vtpm, there is a method called + * sml-handover which is run during kernel init even before + * device tree is setup. This sml-handover function takes care + * of endianness and writes to sml-base and sml-size in little + * endian format. For this reason, vtpm doesn't need conversion + * but physical tpm needs the conversion. + */ + if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0) { + size = be32_to_cpup(sizep); + base = be64_to_cpup(basep); + } else { + size = *sizep; + base = *basep; + } + + if (size == 0) { dev_warn(&chip->dev, "%s: Event log area empty\n", __func__); return -EIO; } - log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); + log->bios_event_log = kmalloc(size, GFP_KERNEL); if (!log->bios_event_log) return -ENOMEM; - log->bios_event_log_end = log->bios_event_log + *sizep; + log->bios_event_log_end = log->bios_event_log + size; - memcpy(log->bios_event_log, __va(*basep), *sizep); + memcpy(log->bios_event_log, __va(base), size); return 0; } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 0127af130cb1..c7e1384f1b08 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -159,7 +159,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, irq = tpm_info->irq; if (itpm) - phy->priv.flags |= TPM_TIS_ITPM_POSSIBLE; + phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND; return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg, acpi_dev_handle); @@ -432,7 +432,7 @@ err_pnp: acpi_bus_unregister_driver(&tis_acpi_driver); err_acpi: #endif - platform_device_unregister(force_pdev); + platform_driver_unregister(&tis_drv); err_platform: if (force_pdev) platform_device_unregister(force_pdev); diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 7993678954a2..c0f296b5d413 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -264,7 +264,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int rc, status, burstcnt; size_t count = 0; - bool itpm = priv->flags & TPM_TIS_ITPM_POSSIBLE; + bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND; if (request_locality(chip, 0) < 0) return -EBUSY; @@ -464,6 +464,9 @@ static int probe_itpm(struct tpm_chip *chip) size_t len = sizeof(cmd_getticks); u16 vendor; + if (priv->flags & TPM_TIS_ITPM_WORKAROUND) + return 0; + rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor); if (rc < 0) return rc; @@ -479,12 +482,15 @@ static int probe_itpm(struct tpm_chip *chip) tpm_tis_ready(chip); release_locality(chip, priv->locality, 0); + priv->flags |= TPM_TIS_ITPM_WORKAROUND; + rc = tpm_tis_send_data(chip, cmd_getticks, len); - if (rc == 0) { + if (rc == 0) dev_info(&chip->dev, "Detected an iTPM.\n"); - rc = 1; - } else + else { + priv->flags &= ~TPM_TIS_ITPM_WORKAROUND; rc = -EFAULT; + } out: tpm_tis_ready(chip); @@ -552,7 +558,8 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip) if (chip->flags & TPM_CHIP_FLAG_TPM2) return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); else - return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc); + return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, + 0); } /* Register the IRQ and issue a command that will cause an interrupt. If an @@ -740,15 +747,10 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2", vendor >> 16, rid); - if (!(priv->flags & TPM_TIS_ITPM_POSSIBLE)) { - probe = probe_itpm(chip); - if (probe < 0) { - rc = -ENODEV; - goto out_err; - } - - if (!!probe) - priv->flags |= TPM_TIS_ITPM_POSSIBLE; + probe = probe_itpm(chip); + if (probe < 0) { + rc = -ENODEV; + goto out_err; } /* Figure out the capabilities */ diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index 9191aabbf9c2..e2212f021a02 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -80,7 +80,7 @@ enum tis_defaults { #define TPM_RID(l) (0x0F04 | ((l) << 12)) enum tpm_tis_flags { - TPM_TIS_ITPM_POSSIBLE = BIT(0), + TPM_TIS_ITPM_WORKAROUND = BIT(0), }; struct tpm_tis_data { diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c index dbaad9c681e3..5292e5768a7e 100644 --- a/drivers/char/tpm/tpm_tis_spi.c +++ b/drivers/char/tpm/tpm_tis_spi.c @@ -33,7 +33,6 @@ #include <linux/acpi.h> #include <linux/freezer.h> -#include <linux/module.h> #include <linux/spi/spi.h> #include <linux/gpio.h> #include <linux/of_irq.h> diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 5463b58af26e..751059d2140a 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -65,7 +65,12 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev); /** * vtpm_proxy_fops_read - Read TPM commands on 'server side' * - * Return value: + * @filp: file pointer + * @buf: read buffer + * @count: number of bytes to read + * @off: offset + * + * Return: * Number of bytes read or negative error code */ static ssize_t vtpm_proxy_fops_read(struct file *filp, char __user *buf, @@ -115,7 +120,12 @@ static ssize_t vtpm_proxy_fops_read(struct file *filp, char __user *buf, /** * vtpm_proxy_fops_write - Write TPM responses on 'server side' * - * Return value: + * @filp: file pointer + * @buf: write buffer + * @count: number of bytes to write + * @off: offset + * + * Return: * Number of bytes read or negative error value */ static ssize_t vtpm_proxy_fops_write(struct file *filp, const char __user *buf, @@ -155,10 +165,12 @@ static ssize_t vtpm_proxy_fops_write(struct file *filp, const char __user *buf, } /* - * vtpm_proxy_fops_poll: Poll status on 'server side' + * vtpm_proxy_fops_poll - Poll status on 'server side' + * + * @filp: file pointer + * @wait: poll table * - * Return value: - * Poll flags + * Return: Poll flags */ static unsigned int vtpm_proxy_fops_poll(struct file *filp, poll_table *wait) { @@ -185,6 +197,8 @@ static unsigned int vtpm_proxy_fops_poll(struct file *filp, poll_table *wait) /* * vtpm_proxy_fops_open - Open vTPM device on 'server side' * + * @filp: file pointer + * * Called when setting up the anonymous file descriptor */ static void vtpm_proxy_fops_open(struct file *filp) @@ -196,8 +210,9 @@ static void vtpm_proxy_fops_open(struct file *filp) /** * vtpm_proxy_fops_undo_open - counter-part to vtpm_fops_open + * Call to undo vtpm_proxy_fops_open * - * Call to undo vtpm_proxy_fops_open + *@proxy_dev: tpm proxy device */ static void vtpm_proxy_fops_undo_open(struct proxy_dev *proxy_dev) { @@ -212,9 +227,11 @@ static void vtpm_proxy_fops_undo_open(struct proxy_dev *proxy_dev) } /* - * vtpm_proxy_fops_release: Close 'server side' + * vtpm_proxy_fops_release - Close 'server side' * - * Return value: + * @inode: inode + * @filp: file pointer + * Return: * Always returns 0. */ static int vtpm_proxy_fops_release(struct inode *inode, struct file *filp) @@ -245,7 +262,10 @@ static const struct file_operations vtpm_proxy_fops = { /* * Called when core TPM driver reads TPM responses from 'server side' * - * Return value: + * @chip: tpm chip to use + * @buf: receive buffer + * @count: bytes to read + * Return: * Number of TPM response bytes read, negative error value otherwise */ static int vtpm_proxy_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count) @@ -282,7 +302,11 @@ out: /* * Called when core TPM driver forwards TPM requests to 'server side'. * - * Return value: + * @chip: tpm chip to use + * @buf: send buffer + * @count: bytes to send + * + * Return: * 0 in case of success, negative error value otherwise. */ static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count) @@ -442,7 +466,7 @@ static inline void vtpm_proxy_delete_proxy_dev(struct proxy_dev *proxy_dev) /* * Create a /dev/tpm%d and 'server side' file descriptor pair * - * Return value: + * Return: * Returns file pointer on success, an error value otherwise */ static struct file *vtpm_proxy_create_device( @@ -571,7 +595,7 @@ static long vtpmx_ioc_new_dev(struct file *file, unsigned int ioctl, /* * vtpmx_fops_ioctl: ioctl on /dev/vtpmx * - * Return value: + * Return: * Returns 0 on success, a negative error code otherwise. */ static long vtpmx_fops_ioctl(struct file *f, unsigned int ioctl, diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 5aaa268f3a78..656e8af95d52 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -289,7 +289,6 @@ static int tpmfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct tpm_private *priv; - struct tpm_chip *chip; int rv; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -306,7 +305,6 @@ static int tpmfront_probe(struct xenbus_device *dev, rv = setup_ring(dev, priv); if (rv) { - chip = dev_get_drvdata(&dev->dev); ring_free(priv); return rv; } |