Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tpm: add securityfs support for TPM 2.0 firmware event log

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>

authored by

Nayna Jain and committed by
Jarkko Sakkinen
4d23cc32 e46e22f1

+279 -22
+1 -1
drivers/char/tpm/Makefile
··· 3 3 # 4 4 obj-$(CONFIG_TCG_TPM) += tpm.o 5 5 tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ 6 - tpm_eventlog.o 6 + tpm1_eventlog.o tpm2_eventlog.o 7 7 tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o 8 8 tpm-$(CONFIG_OF) += tpm_of.o 9 9 obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
+5 -2
drivers/char/tpm/tpm.h
··· 36 36 #include <linux/highmem.h> 37 37 #include <crypto/hash_info.h> 38 38 39 - #include "tpm_eventlog.h" 40 - 41 39 enum tpm_const { 42 40 TPM_MINOR = 224, /* officially assigned */ 43 41 TPM_BUFSIZE = 4096, ··· 147 149 TPM_CHIP_FLAG_IRQ = BIT(2), 148 150 TPM_CHIP_FLAG_VIRTUAL = BIT(3), 149 151 TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), 152 + }; 153 + 154 + struct tpm_bios_log { 155 + void *bios_event_log; 156 + void *bios_event_log_end; 150 157 }; 151 158 152 159 struct tpm_chip_seqops {
+203
drivers/char/tpm/tpm2_eventlog.c
··· 1 + /* 2 + * Copyright (C) 2016 IBM Corporation 3 + * 4 + * Authors: 5 + * Nayna Jain <nayna@linux.vnet.ibm.com> 6 + * 7 + * Access to TPM 2.0 event log as written by Firmware. 8 + * It assumes that writer of event log has followed TCG Specification 9 + * for Family "2.0" and written the event data in little endian. 10 + * With that, it doesn't need any endian conversion for structure 11 + * content. 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * as published by the Free Software Foundation; either version 16 + * 2 of the License, or (at your option) any later version. 17 + */ 18 + 19 + #include <linux/seq_file.h> 20 + #include <linux/fs.h> 21 + #include <linux/security.h> 22 + #include <linux/module.h> 23 + #include <linux/slab.h> 24 + 25 + #include "tpm.h" 26 + #include "tpm_eventlog.h" 27 + 28 + /* 29 + * calc_tpm2_event_size() - calculate the event size, where event 30 + * is an entry in the TPM 2.0 event log. The event is of type Crypto 31 + * Agile Log Entry Format as defined in TCG EFI Protocol Specification 32 + * Family "2.0". 33 + 34 + * @event: event whose size is to be calculated. 35 + * @event_header: the first event in the event log. 36 + * 37 + * Returns size of the event. If it is an invalid event, returns 0. 38 + */ 39 + static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, 40 + struct tcg_pcr_event *event_header) 41 + { 42 + struct tcg_efi_specid_event *efispecid; 43 + struct tcg_event_field *event_field; 44 + void *marker; 45 + void *marker_start; 46 + u32 halg_size; 47 + size_t size; 48 + u16 halg; 49 + int i; 50 + int j; 51 + 52 + marker = event; 53 + marker_start = marker; 54 + marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) 55 + + sizeof(event->count); 56 + 57 + efispecid = (struct tcg_efi_specid_event *)event_header->event; 58 + 59 + for (i = 0; (i < event->count) && (i < TPM2_ACTIVE_PCR_BANKS); 60 + i++) { 61 + halg_size = sizeof(event->digests[i].alg_id); 62 + memcpy(&halg, marker, halg_size); 63 + marker = marker + halg_size; 64 + for (j = 0; (j < efispecid->num_algs); j++) { 65 + if (halg == efispecid->digest_sizes[j].alg_id) { 66 + marker = marker + 67 + efispecid->digest_sizes[j].digest_size; 68 + break; 69 + } 70 + } 71 + } 72 + 73 + event_field = (struct tcg_event_field *)marker; 74 + marker = marker + sizeof(event_field->event_size) 75 + + event_field->event_size; 76 + size = marker - marker_start; 77 + 78 + if ((event->event_type == 0) && (event_field->event_size == 0)) 79 + return 0; 80 + 81 + return size; 82 + } 83 + 84 + static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) 85 + { 86 + struct tpm_chip *chip = m->private; 87 + struct tpm_bios_log *log = &chip->log; 88 + void *addr = log->bios_event_log; 89 + void *limit = log->bios_event_log_end; 90 + struct tcg_pcr_event *event_header; 91 + struct tcg_pcr_event2 *event; 92 + size_t size; 93 + int i; 94 + 95 + event_header = addr; 96 + size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) 97 + + event_header->event_size; 98 + 99 + if (*pos == 0) { 100 + if (addr + size < limit) { 101 + if ((event_header->event_type == 0) && 102 + (event_header->event_size == 0)) 103 + return NULL; 104 + return SEQ_START_TOKEN; 105 + } 106 + } 107 + 108 + if (*pos > 0) { 109 + addr += size; 110 + event = addr; 111 + size = calc_tpm2_event_size(event, event_header); 112 + if ((addr + size >= limit) || (size == 0)) 113 + return NULL; 114 + } 115 + 116 + for (i = 0; i < (*pos - 1); i++) { 117 + event = addr; 118 + size = calc_tpm2_event_size(event, event_header); 119 + 120 + if ((addr + size >= limit) || (size == 0)) 121 + return NULL; 122 + addr += size; 123 + } 124 + 125 + return addr; 126 + } 127 + 128 + static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, 129 + loff_t *pos) 130 + { 131 + struct tcg_pcr_event *event_header; 132 + struct tcg_pcr_event2 *event; 133 + struct tpm_chip *chip = m->private; 134 + struct tpm_bios_log *log = &chip->log; 135 + void *limit = log->bios_event_log_end; 136 + size_t event_size; 137 + void *marker; 138 + 139 + event_header = log->bios_event_log; 140 + 141 + if (v == SEQ_START_TOKEN) { 142 + event_size = sizeof(struct tcg_pcr_event) - 143 + sizeof(event_header->event) + event_header->event_size; 144 + marker = event_header; 145 + } else { 146 + event = v; 147 + event_size = calc_tpm2_event_size(event, event_header); 148 + if (event_size == 0) 149 + return NULL; 150 + marker = event; 151 + } 152 + 153 + marker = marker + event_size; 154 + if (marker >= limit) 155 + return NULL; 156 + v = marker; 157 + event = v; 158 + 159 + event_size = calc_tpm2_event_size(event, event_header); 160 + if (((v + event_size) >= limit) || (event_size == 0)) 161 + return NULL; 162 + 163 + (*pos)++; 164 + return v; 165 + } 166 + 167 + static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) 168 + { 169 + } 170 + 171 + static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) 172 + { 173 + struct tpm_chip *chip = m->private; 174 + struct tpm_bios_log *log = &chip->log; 175 + struct tcg_pcr_event *event_header = log->bios_event_log; 176 + struct tcg_pcr_event2 *event = v; 177 + void *temp_ptr; 178 + size_t size; 179 + 180 + if (v == SEQ_START_TOKEN) { 181 + size = sizeof(struct tcg_pcr_event) - 182 + sizeof(event_header->event) + event_header->event_size; 183 + 184 + temp_ptr = event_header; 185 + 186 + if (size > 0) 187 + seq_write(m, temp_ptr, size); 188 + } else { 189 + size = calc_tpm2_event_size(event, event_header); 190 + temp_ptr = event; 191 + if (size > 0) 192 + seq_write(m, temp_ptr, size); 193 + } 194 + 195 + return 0; 196 + } 197 + 198 + const struct seq_operations tpm2_binary_b_measurements_seqops = { 199 + .start = tpm2_bios_measurements_start, 200 + .next = tpm2_bios_measurements_next, 201 + .stop = tpm2_bios_measurements_stop, 202 + .show = tpm2_binary_bios_measurements_show, 203 + };
+3
drivers/char/tpm/tpm_acpi.c
··· 54 54 u64 len, start; 55 55 struct tpm_bios_log *log; 56 56 57 + if (chip->flags & TPM_CHIP_FLAG_TPM2) 58 + return -ENODEV; 59 + 57 60 log = &chip->log; 58 61 59 62 /* Unfortuntely ACPI does not associate the event log with a specific
+21 -14
drivers/char/tpm/tpm_eventlog.c drivers/char/tpm/tpm1_eventlog.c
··· 390 390 unsigned int cnt; 391 391 int rc = 0; 392 392 393 - if (chip->flags & TPM_CHIP_FLAG_TPM2) 394 - return 0; 395 - 396 393 rc = tpm_read_log(chip); 397 394 if (rc) 398 395 return rc; ··· 404 407 cnt++; 405 408 406 409 chip->bin_log_seqops.chip = chip; 407 - chip->bin_log_seqops.seqops = &tpm_binary_b_measurements_seqops; 410 + if (chip->flags & TPM_CHIP_FLAG_TPM2) 411 + chip->bin_log_seqops.seqops = 412 + &tpm2_binary_b_measurements_seqops; 413 + else 414 + chip->bin_log_seqops.seqops = 415 + &tpm_binary_b_measurements_seqops; 416 + 408 417 409 418 chip->bios_dir[cnt] = 410 419 securityfs_create_file("binary_bios_measurements", ··· 421 418 goto err; 422 419 cnt++; 423 420 424 - chip->ascii_log_seqops.chip = chip; 425 - chip->ascii_log_seqops.seqops = &tpm_ascii_b_measurements_seqops; 421 + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { 426 422 427 - chip->bios_dir[cnt] = 428 - securityfs_create_file("ascii_bios_measurements", 429 - 0440, chip->bios_dir[0], 430 - (void *)&chip->ascii_log_seqops, 431 - &tpm_bios_measurements_ops); 432 - if (IS_ERR(chip->bios_dir[cnt])) 433 - goto err; 434 - cnt++; 423 + chip->ascii_log_seqops.chip = chip; 424 + chip->ascii_log_seqops.seqops = 425 + &tpm_ascii_b_measurements_seqops; 426 + 427 + chip->bios_dir[cnt] = 428 + securityfs_create_file("ascii_bios_measurements", 429 + 0440, chip->bios_dir[0], 430 + (void *)&chip->ascii_log_seqops, 431 + &tpm_bios_measurements_ops); 432 + if (IS_ERR(chip->bios_dir[cnt])) 433 + goto err; 434 + cnt++; 435 + } 435 436 436 437 return 0; 437 438
+46 -5
drivers/char/tpm/tpm_eventlog.h
··· 2 2 #ifndef __TPM_EVENTLOG_H__ 3 3 #define __TPM_EVENTLOG_H__ 4 4 5 + #include <crypto/hash_info.h> 6 + 5 7 #define TCG_EVENT_NAME_LEN_MAX 255 6 8 #define MAX_TEXT_EVENT 1000 /* Max event string length */ 7 9 #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ 10 + #define TPM2_ACTIVE_PCR_BANKS 3 8 11 9 12 #ifdef CONFIG_PPC64 10 13 #define do_endian_conversion(x) be32_to_cpu(x) ··· 18 15 enum bios_platform_class { 19 16 BIOS_CLIENT = 0x00, 20 17 BIOS_SERVER = 0x01, 21 - }; 22 - 23 - struct tpm_bios_log { 24 - void *bios_event_log; 25 - void *bios_event_log_end; 26 18 }; 27 19 28 20 struct tcpa_event { ··· 70 72 POST_CONTENTS, 71 73 HOST_TABLE_OF_DEVICES, 72 74 }; 75 + 76 + /* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */ 77 + 78 + struct tcg_efi_specid_event_algs { 79 + u16 alg_id; 80 + u16 digest_size; 81 + } __packed; 82 + 83 + struct tcg_efi_specid_event { 84 + u8 signature[16]; 85 + u32 platform_class; 86 + u8 spec_version_minor; 87 + u8 spec_version_major; 88 + u8 spec_errata; 89 + u8 uintnsize; 90 + u32 num_algs; 91 + struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS]; 92 + u8 vendor_info_size; 93 + u8 vendor_info[0]; 94 + } __packed; 95 + 96 + struct tcg_pcr_event { 97 + u32 pcr_idx; 98 + u32 event_type; 99 + u8 digest[20]; 100 + u32 event_size; 101 + u8 event[0]; 102 + } __packed; 103 + 104 + struct tcg_event_field { 105 + u32 event_size; 106 + u8 event[0]; 107 + } __packed; 108 + 109 + struct tcg_pcr_event2 { 110 + u32 pcr_idx; 111 + u32 event_type; 112 + u32 count; 113 + struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS]; 114 + struct tcg_event_field event; 115 + } __packed; 116 + 117 + extern const struct seq_operations tpm2_binary_b_measurements_seqops; 73 118 74 119 #if defined(CONFIG_ACPI) 75 120 int tpm_read_log_acpi(struct tpm_chip *chip);