On Tue, Aug 30, 2016 at 12:50:19AM -0400, Nayna Jain wrote: > Adds securityfs support for TPM2.0. > This patch add supports only for binary_bios_measurements.
You should use more time to your commit messages. Descriptions like this are unacceptable. > Signed-off-by: Nayna Jain <na...@linux.vnet.ibm.com> > --- > drivers/char/tpm/Makefile | 2 +- > drivers/char/tpm/tpm2.h | 85 +++++++++++++ > drivers/char/tpm/tpm2_eventlog.c | 224 > +++++++++++++++++++++++++++++++++++ > drivers/char/tpm/tpm_eventlog_init.c | 28 +++-- > drivers/char/tpm/tpm_of.c | 42 ++++--- > 5 files changed, 357 insertions(+), 24 deletions(-) > create mode 100644 drivers/char/tpm/tpm2.h > create mode 100644 drivers/char/tpm/tpm2_eventlog.c > > diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile > index 200b957..b10316d 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 tpm_eventlog_init.o > + tpm_eventlog.o tpm_eventlog_init.o tpm2_eventlog.o > > tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o > tpm-$(CONFIG_OF) += tpm_of.o > diff --git a/drivers/char/tpm/tpm2.h b/drivers/char/tpm/tpm2.h > new file mode 100644 > index 0000000..38a8073 > --- /dev/null > +++ b/drivers/char/tpm/tpm2.h > @@ -0,0 +1,85 @@ > +#ifndef __TPM2_H__ > +#define __TPM2_H__ > + > +#define TPM_ALG_SHA1_DIGEST_SIZE 20 > +#define TPM_ALG_SHA256_DIGEST_SIZE 32 > +#define TPM_ALG_SHA384_DIGEST_SIZE 48 > + > +#define HASH_COUNT 3 > +#define MAX_TPM_LOG_MSG 128 > + > +/** > + * All the structures related to Event Log are taken from TCG EFI Protocol > + * Specification, Family "2.0". Document is available on link > + * http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ > + * Information is also available on TCG PC Client Platform Firmware Profile > + * Specification, Family "2.0" > + * Detailed digest structures for TPM2.0 are defined in document > + * Trusted Platform Module Library Part 2: Structures, Family "2.0". > + */ > + > +/* Event log header algorithm spec. */ > +struct tcg_efispecideventalgorithmsize { > + u16 algorithm_id; > + u16 digest_size; > +} __packed; > + > +/* Event log header data. */ > +struct tcg_efispecideventstruct { > + u8 signature[16]; > + u32 platform_class; > + u8 spec_version_minor; > + u8 spec_version_major; > + u8 spec_errata; > + u8 uintnsize; > + u32 num_algs; > + struct tcg_efispecideventalgorithmsize digest_sizes[HASH_COUNT]; > + u8 vendor_info_size; > + u8 vendor_info[0]; > +} __packed; > + > +/* Header entry for eventlog. */ > +struct tcg_pcr_event { > + u32 pcr_index; > + u32 event_type; > + u8 digest[20]; > + u32 event_size; > + u8 event[MAX_TPM_LOG_MSG]; > +} __packed; > + > +/* Digest union for crypto agility. */ > +union tpmu_ha { > + u8 sha1[TPM_ALG_SHA1_DIGEST_SIZE]; > + u8 sha256[TPM_ALG_SHA256_DIGEST_SIZE]; > + u8 sha384[TPM_ALG_SHA384_DIGEST_SIZE]; > +} __packed; > + > +/* Crypto Agile algorithm and respective digest. */ > +struct tpmt_ha { > + u16 algorithm_id; > + union tpmu_ha digest; > +} __packed; > + > +/* Crypto agile digests list. */ > +struct tpml_digest_values { > + u32 count; > + struct tpmt_ha digests[HASH_COUNT]; > +} __packed; > + > +/* Event field structure. */ > +struct tcg_event_field { > + u32 event_size; > + u8 event[MAX_TPM_LOG_MSG]; > +} __packed; > + > +/* Crypto agile log entry format for TPM 2.0. */ > +struct tcg_pcr_event2 { > + u32 pcr_index; > + u32 event_type; > + struct tpml_digest_values digests; > + struct tcg_event_field event; > +} __packed; > + > +extern const struct seq_operations tpm2_binary_b_measurments_seqops; > + > +#endif > diff --git a/drivers/char/tpm/tpm2_eventlog.c > b/drivers/char/tpm/tpm2_eventlog.c > new file mode 100644 > index 0000000..f1e8c4a > --- /dev/null > +++ b/drivers/char/tpm/tpm2_eventlog.c > @@ -0,0 +1,224 @@ > +/* > + * Copyright (C) 2016 IBM Corporation > + * > + * Authors: > + * Nayna Jain <na...@linux.vnet.ibm.com> > + > + * Access to TPM2.0 event log as written by Firmware. > + * It assumes that writer of event log has followed TCG Spec 2.0 > + * has written the event struct 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 "tpm2.h" > +#include "tpm_eventlog.h" > + > + > +static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, > + struct tcg_pcr_event *event_header) > +{ > + struct tcg_efispecideventstruct *efispecid; > + struct tcg_event_field *event_field; > + void *marker, *marker_start; > + int j; > + size_t size = 0; > + > + /* > + * NOTE: TPM2.0 allows support for extend to multiple PCR Banks. > + * This implies that eventlog also has multiple digest values > + * one for each PCR Bank. This is called Crypto Agile Log Entry > + * Format. Current support implementation is for SHA1 and SHA256. > + * Number of digest values are identified by parsing first > + * structure stored in event log also called event header. > + * Further, the eventlog is written in packed form so to calculate > + * offset it is important to know the type of algorithm used. > + * Eg. 1: > + * digest_values.count = 1; > + * digest_values.digest[0].algorithm_id = sha1; > + * digest_values.digest[0].digest.sha1 = {20 bytes raw data}; > + * Offset of eventsize is sizeof(count) + sizeof(algorithm_id) + 20 > + * > + * Eg. 2: > + * digest_values.count = 1; > + * digest_values.digest[0].algorithm_id = sha256; > + * digest_values.digest[0].digest.sha1 = {32 bytes raw data}; > + * Offset of eventsize is sizeof(count) + sizeof(algorithm_id) + 32 > + > + * Eg. 3: > + * digest_values.count = 2; > + * digest_values.digest[0].algorithm_id = sha1; > + * digest_values.digest[0].digest.sha1 = {20 bytes raw data}; > + * digest_values.digest[1].algorithm_id = sha256; > + * digest_values.digest[1].digest.sha256 = {32 bytes raw data}; > + * Offset of eventsize is sizeof(count) + sizeof(algorithm_id) + 20 > + * + sizeof(algorithm_id) + 32; > + * > + * So, it implies that offset of event_size can vary based on digest > + * values as defined by vendor. And so we have to calculate the > + * offset by parsing through number and type of digests being used. > + * And this is the purpose of using *marker to traverse the structure > + * and calculate the offset of event_size. This function uses *marker > + * to parse and calculate the dynamic size of the whole event structure. > + */ > + > + marker = event; > + marker_start = marker; > + marker = marker + sizeof(event->pcr_index) + sizeof(event->event_type) > + + sizeof(event->digests.count); > + > + efispecid = (struct tcg_efispecideventstruct *) event_header->event; > + > + for (j = 0; (j < efispecid->num_algs) && (j < HASH_COUNT); j++) { > + marker = marker > + + sizeof(efispecid->digest_sizes[j].algorithm_id); > + marker = marker + efispecid->digest_sizes[j].digest_size; > + } > + > + 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_bios_log *log = m->private; > + void *addr = log->bios_event_log; > + void *limit = log->bios_event_log_end; > + struct tcg_pcr_event *event_header; > + struct tcg_pcr_event2 *event; > + int i; > + size_t size = 0; > + > + 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; > + } > + > + /* read over *pos measurements */ > + 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_bios_log *log = m->private; > + void *limit = log->bios_event_log_end; > + void *marker; > + size_t event_size = 0; > + > + 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_bios_log *log = m->private; > + struct tcg_pcr_event *event_header = log->bios_event_log; > + struct tcg_pcr_event2 *event = v; > + void *temp_ptr; > + size_t size = 0; > + > + 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_measurments_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_eventlog_init.c > b/drivers/char/tpm/tpm_eventlog_init.c > index 038771a..9afeb3d 100644 > --- a/drivers/char/tpm/tpm_eventlog_init.c > +++ b/drivers/char/tpm/tpm_eventlog_init.c > @@ -28,6 +28,7 @@ > #include <linux/slab.h> > > #include "tpm.h" > +#include "tpm2.h" > #include "tpm_eventlog.h" > > static int tpm_bios_measurements_release(struct inode *inode, > @@ -94,6 +95,7 @@ int read_log(struct tpm_chip *chip) > void tpm_bios_log_setup(struct tpm_chip *chip) > { > const char *name = dev_name(&chip->dev); > + void *seq_ops; > int rc = 0; > > rc = read_log(chip); > @@ -108,23 +110,31 @@ void tpm_bios_log_setup(struct tpm_chip *chip) > chip->bios_dir[chip->bios_dir_count]->d_inode->i_private = chip; > chip->bios_dir_count++; > > + if (chip->flags & TPM_CHIP_FLAG_TPM2) > + seq_ops = (void *)&tpm2_binary_b_measurments_seqops; > + else > + seq_ops = (void *)&tpm_binary_b_measurments_seqops; > + > + > chip->bios_dir[chip->bios_dir_count] = > securityfs_create_file("binary_bios_measurements", > S_IRUSR | S_IRGRP, chip->bios_dir[0], > - (void *)&tpm_binary_b_measurments_seqops, > + seq_ops, > &tpm_bios_measurements_ops); > if (is_bad(chip->bios_dir[chip->bios_dir_count])) > goto err; > chip->bios_dir_count++; > > - chip->bios_dir[chip->bios_dir_count] = > - securityfs_create_file("ascii_bios_measurements", > - S_IRUSR | S_IRGRP, chip->bios_dir[0], > - (void *)&tpm_ascii_b_measurments_seqops, > - &tpm_bios_measurements_ops); > - if (is_bad(chip->bios_dir[chip->bios_dir_count])) > - goto err; > - chip->bios_dir_count++; > + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { > + chip->bios_dir[chip->bios_dir_count] = > + securityfs_create_file("ascii_bios_measurements", > + S_IRUSR | S_IRGRP, chip->bios_dir[0], > + (void *)&tpm_ascii_b_measurments_seqops, > + &tpm_bios_measurements_ops); > + if (is_bad(chip->bios_dir[chip->bios_dir_count])) > + goto err; > + chip->bios_dir_count++; > + } > > return; > > diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c > index 4e4eed7..2fc58fe 100644 > --- a/drivers/char/tpm/tpm_of.c > +++ b/drivers/char/tpm/tpm_of.c > @@ -15,12 +15,10 @@ > * > */ > > -#include <linux/seq_file.h> > -#include <linux/fs.h> > -#include <linux/security.h> > -#include <linux/module.h> > #include <linux/slab.h> > +#include <linux/of_device.h> > #include <linux/of.h> > +#include <linux/string.h> > > #include "tpm.h" > #include "tpm_eventlog.h" > @@ -30,44 +28,60 @@ int read_log_of(struct tpm_chip *chip) > struct device_node *np; > const u32 *sizep; > const u64 *basep; > + const struct of_device_id *of_id; > + const char *compat; > + u32 log_size; > > if (chip->dev.of_node) > np = chip->dev.of_node; > if (!np) { > - dev_dbg(&chip->dev, "%s: ERROR - IBMVTPM not supported\n", > + dev_dbg(&chip->dev, "%s: ERROR - TPM not supported\n", > __func__); > return -ENODEV; > } > > + compat = of_get_property(np, "compatible", NULL); > + if (compat == NULL) { > + dev_dbg(&chip->dev, "%s: ERROR - Compatible device not found", > + __func__); > + return -EIO; > + } > + > sizep = of_get_property(np, "linux,sml-size", NULL); > if (sizep == NULL) { > dev_dbg(&chip->dev, "%s: ERROR - SML size not found\n", > __func__); > - goto cleanup_eio; > + return -EIO; > } > if (*sizep == 0) { > dev_dbg(&chip->dev, "%s: ERROR - event log area empty\n", > __func__); > - goto cleanup_eio; > + return -EIO; > } > > + if (!strcasecmp(compat, "IBM,vtpm")) > + log_size = *sizep; > + else > + log_size = be32_to_cpup(sizep); > + > basep = of_get_property(np, "linux,sml-base", NULL); > if (basep == NULL) { > dev_dbg(&chip->dev, "%s: ERROR - SML not found\n", __func__); > - goto cleanup_eio; > + return -EIO; > } > > - chip->log.bios_event_log = kmalloc(*sizep, GFP_KERNEL); > + chip->log.bios_event_log = kmalloc(log_size, GFP_KERNEL); > if (!chip->log.bios_event_log) { > return -ENOMEM; > } > > - chip->log.bios_event_log_end = chip->log.bios_event_log + *sizep; > + chip->log.bios_event_log_end = chip->log.bios_event_log + log_size; > > - memcpy(chip->log.bios_event_log, __va(*basep), *sizep); > + if (!strcasecmp(compat, "IBM,vtpm")) > + memcpy(chip->log.bios_event_log, __va(*basep), log_size); > + else > + memcpy(chip->log.bios_event_log, __va(be64_to_cpup(basep)), > + log_size); > > return 0; > - > -cleanup_eio: > - return -EIO; > } > -- > 2.5.0 > > > ------------------------------------------------------------------------------ > _______________________________________________ > tpmdd-devel mailing list > tpmdd-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/tpmdd-devel /Jarkko ------------------------------------------------------------------------------ _______________________________________________ tpmdd-devel mailing list tpmdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tpmdd-devel