]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
tpm: add securityfs support for TPM 2.0 firmware event log
authorNayna Jain <nayna@linux.vnet.ibm.com>
Mon, 23 Jan 2017 07:26:27 +0000 (02:26 -0500)
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Fri, 3 Feb 2017 20:03:14 +0000 (22:03 +0200)
Unlike the device driver support for TPM 1.2, the TPM 2.0 does
not support the securityfs pseudo files for displaying the
firmware event log.

This patch enables support for providing the TPM 2.0 event log in
binary form. TPM 2.0 event log supports a crypto agile format that
records multiple digests, which is different from TPM 1.2. This
patch enables the tpm_bios_log_setup for TPM 2.0  and adds the
event log parser which understand the TPM 2.0 crypto agile format.

Signed-off-by: Nayna Jain <nayna@linux.vnet.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Kenneth Goldman <kgold@linux.vnet.ibm.com>
Tested-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
drivers/char/tpm/Makefile
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm1_eventlog.c [moved from drivers/char/tpm/tpm_eventlog.c with 95% similarity]
drivers/char/tpm/tpm2_eventlog.c [new file with mode: 0644]
drivers/char/tpm/tpm_acpi.c
drivers/char/tpm/tpm_eventlog.h

index a05b1ebd0b261d0b81c328de008cd5ffced3e70b..3d386a8c579f0961ac0b38ab438f3352084a1649 100644 (file)
@@ -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
index 4b7eca90e17323c4148d126091619d986f2bff4c..bff37be04b46ca238539b4178430ac9a7e200e3b 100644 (file)
@@ -36,8 +36,6 @@
 #include <linux/highmem.h>
 #include <crypto/hash_info.h>
 
-#include "tpm_eventlog.h"
-
 enum tpm_const {
        TPM_MINOR = 224,        /* officially assigned */
        TPM_BUFSIZE = 4096,
@@ -151,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;
similarity index 95%
rename from drivers/char/tpm/tpm_eventlog.c
rename to drivers/char/tpm/tpm1_eventlog.c
index 11bb1138a8282ebf73fb360c3ea873731d54dd35..9a8605e500b5b3d560eea59a4ed15c75f998c869 100644 (file)
@@ -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_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c
new file mode 100644 (file)
index 0000000..513897c
--- /dev/null
@@ -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,
+};
index b7718c95fd0b48cdd0abf074b462568ed22f57b9..169edf3ce86d9df8a5c2b923ab94d08f60439060 100644 (file)
@@ -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
index 1660d74ea79a3a436ef5a1bc8a293f5d52f1e771..b4b5495592035bbc2996be216404b12c5c9287c5 100644 (file)
@@ -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