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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'tpmdd-next-20190625' of git://git.infradead.org/users/jjs/linux-tpmdd

Pull tpm updates from Jarkko Sakkinen:
"This contains two critical bug fixes and support for obtaining TPM
events triggered by ExitBootServices().

For the latter I have to give a quite verbose explanation not least
because I had to revisit all the details myself to remember what was
going on in Matthew's patches.

The preboot software stack maintains an event log that gets entries
every time something gets hashed to any of the PCR registers. What
gets hashed could be a component to be run or perhaps log of some
actions taken just to give couple of coarse examples. In general,
anything relevant for the boot process that the preboot software does
gets hashed and a log entry with a specific event type [1].

The main application for this is remote attestation and the reason why
it is useful is nicely put in the very first section of [1]:

"Attestation is used to provide information about the platform’s
state to a challenger. However, PCR contents are difficult to
interpret; therefore, attestation is typically more useful when
the PCR contents are accompanied by a measurement log. While not
trusted on their own, the measurement log contains a richer set of
information than do the PCR contents. The PCR contents are used to
provide the validation of the measurement log."

Because EFI_TCG2_PROTOCOL.GetEventLog() is not available after calling
ExitBootServices(), Linux EFI stub copies the event log to a custom
configuration table. Unfortunately, ExitBootServices() also generates
events and obviously these events do not get copied to that table.
Luckily firmware does this for us by providing a configuration table
identified by EFI_TCG2_FINAL_EVENTS_TABLE_GUID.

This essentially contains necessary changes to provide the full event
log for the use the user space that is concatenated from these two
partial event logs [2]"

[1] https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/
[2] The final concatenation is done in drivers/char/tpm/eventlog/efi.c

* tag 'tpmdd-next-20190625' of git://git.infradead.org/users/jjs/linux-tpmdd:
tpm: Don't duplicate events from the final event log in the TCG2 log
Abstract out support for locating an EFI config table
tpm: Fix TPM 1.2 Shutdown sequence to prevent future TPM operations
efi: Attempt to get the TCG2 event log in the boot stub
tpm: Append the final event log to the TPM event log
tpm: Reserve the TPM final events table
tpm: Abstract crypto agile event size calculations
tpm: Actually fail on TPM errors during "get random"

+378 -99
+52 -7
drivers/char/tpm/eventlog/efi.c
··· 16 16 int tpm_read_log_efi(struct tpm_chip *chip) 17 17 { 18 18 19 + struct efi_tcg2_final_events_table *final_tbl = NULL; 19 20 struct linux_efi_tpm_eventlog *log_tbl; 20 21 struct tpm_bios_log *log; 21 22 u32 log_size; 22 23 u8 tpm_log_version; 24 + void *tmp; 25 + int ret; 23 26 24 27 if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) 25 28 return -ENODEV; ··· 50 47 51 48 /* malloc EventLog space */ 52 49 log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL); 53 - if (!log->bios_event_log) 54 - goto err_memunmap; 50 + if (!log->bios_event_log) { 51 + ret = -ENOMEM; 52 + goto out; 53 + } 54 + 55 55 log->bios_event_log_end = log->bios_event_log + log_size; 56 - 57 56 tpm_log_version = log_tbl->version; 58 - memunmap(log_tbl); 59 - return tpm_log_version; 60 57 61 - err_memunmap: 58 + ret = tpm_log_version; 59 + 60 + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || 61 + efi_tpm_final_log_size == 0 || 62 + tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) 63 + goto out; 64 + 65 + final_tbl = memremap(efi.tpm_final_log, 66 + sizeof(*final_tbl) + efi_tpm_final_log_size, 67 + MEMREMAP_WB); 68 + if (!final_tbl) { 69 + pr_err("Could not map UEFI TPM final log\n"); 70 + kfree(log->bios_event_log); 71 + ret = -ENOMEM; 72 + goto out; 73 + } 74 + 75 + efi_tpm_final_log_size -= log_tbl->final_events_preboot_size; 76 + 77 + tmp = krealloc(log->bios_event_log, 78 + log_size + efi_tpm_final_log_size, 79 + GFP_KERNEL); 80 + if (!tmp) { 81 + kfree(log->bios_event_log); 82 + ret = -ENOMEM; 83 + goto out; 84 + } 85 + 86 + log->bios_event_log = tmp; 87 + 88 + /* 89 + * Copy any of the final events log that didn't also end up in the 90 + * main log. Events can be logged in both if events are generated 91 + * between GetEventLog() and ExitBootServices(). 92 + */ 93 + memcpy((void *)log->bios_event_log + log_size, 94 + final_tbl->events + log_tbl->final_events_preboot_size, 95 + efi_tpm_final_log_size); 96 + log->bios_event_log_end = log->bios_event_log + 97 + log_size + efi_tpm_final_log_size; 98 + 99 + out: 100 + memunmap(final_tbl); 62 101 memunmap(log_tbl); 63 - return -ENOMEM; 102 + return ret; 64 103 }
+1 -46
drivers/char/tpm/eventlog/tpm2.c
··· 36 36 static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, 37 37 struct tcg_pcr_event *event_header) 38 38 { 39 - struct tcg_efi_specid_event_head *efispecid; 40 - struct tcg_event_field *event_field; 41 - void *marker; 42 - void *marker_start; 43 - u32 halg_size; 44 - size_t size; 45 - u16 halg; 46 - int i; 47 - int j; 48 - 49 - marker = event; 50 - marker_start = marker; 51 - marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) 52 - + sizeof(event->count); 53 - 54 - efispecid = (struct tcg_efi_specid_event_head *)event_header->event; 55 - 56 - /* Check if event is malformed. */ 57 - if (event->count > efispecid->num_algs) 58 - return 0; 59 - 60 - for (i = 0; i < event->count; 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 += 67 - efispecid->digest_sizes[j].digest_size; 68 - break; 69 - } 70 - } 71 - /* Algorithm without known length. Such event is unparseable. */ 72 - if (j == efispecid->num_algs) 73 - return 0; 74 - } 75 - 76 - event_field = (struct tcg_event_field *)marker; 77 - marker = marker + sizeof(event_field->event_size) 78 - + event_field->event_size; 79 - size = marker - marker_start; 80 - 81 - if ((event->event_type == 0) && (event_field->event_size == 0)) 82 - return 0; 83 - 84 - return size; 39 + return __calc_tpm2_event_size(event, event_header, false); 85 40 } 86 41 87 42 static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
+3 -3
drivers/char/tpm/tpm-chip.c
··· 289 289 { 290 290 struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); 291 291 292 + down_write(&chip->ops_sem); 292 293 if (chip->flags & TPM_CHIP_FLAG_TPM2) { 293 - down_write(&chip->ops_sem); 294 294 if (!tpm_chip_start(chip)) { 295 295 tpm2_shutdown(chip, TPM2_SU_CLEAR); 296 296 tpm_chip_stop(chip); 297 297 } 298 - chip->ops = NULL; 299 - up_write(&chip->ops_sem); 300 298 } 299 + chip->ops = NULL; 300 + up_write(&chip->ops_sem); 301 301 302 302 return 0; 303 303 }
+5 -2
drivers/char/tpm/tpm1-cmd.c
··· 510 510 * 511 511 * Return: 512 512 * * number of bytes read 513 - * * -errno or a TPM return code otherwise 513 + * * -errno (positive TPM return codes are masked to -EIO) 514 514 */ 515 515 int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) 516 516 { ··· 531 531 532 532 rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len), 533 533 "attempting get random"); 534 - if (rc) 534 + if (rc) { 535 + if (rc > 0) 536 + rc = -EIO; 535 537 goto out; 538 + } 536 539 537 540 out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE]; 538 541
+5 -2
drivers/char/tpm/tpm2-cmd.c
··· 297 297 * 298 298 * Return: 299 299 * size of the buffer on success, 300 - * -errno otherwise 300 + * -errno otherwise (positive TPM return codes are masked to -EIO) 301 301 */ 302 302 int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) 303 303 { ··· 324 324 offsetof(struct tpm2_get_random_out, 325 325 buffer), 326 326 "attempting get random"); 327 - if (err) 327 + if (err) { 328 + if (err > 0) 329 + err = -EIO; 328 330 goto out; 331 + } 329 332 330 333 out = (struct tpm2_get_random_out *) 331 334 &buf.data[TPM_HEADER_SIZE];
+2
drivers/firmware/efi/efi.c
··· 52 52 .mem_attr_table = EFI_INVALID_TABLE_ADDR, 53 53 .rng_seed = EFI_INVALID_TABLE_ADDR, 54 54 .tpm_log = EFI_INVALID_TABLE_ADDR, 55 + .tpm_final_log = EFI_INVALID_TABLE_ADDR, 55 56 .mem_reserve = EFI_INVALID_TABLE_ADDR, 56 57 }; 57 58 EXPORT_SYMBOL(efi); ··· 485 484 {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, 486 485 {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, 487 486 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, 487 + {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log}, 488 488 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, 489 489 {NULL_GUID, NULL, NULL}, 490 490 };
+15
drivers/firmware/efi/libstub/efi-stub-helper.c
··· 926 926 fail: 927 927 return status; 928 928 } 929 + 930 + void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid) 931 + { 932 + efi_config_table_t *tables = (efi_config_table_t *)sys_table->tables; 933 + int i; 934 + 935 + for (i = 0; i < sys_table->nr_tables; i++) { 936 + if (efi_guidcmp(tables[i].guid, guid) != 0) 937 + continue; 938 + 939 + return (void *)tables[i].table; 940 + } 941 + 942 + return NULL; 943 + }
+2
drivers/firmware/efi/libstub/efistub.h
··· 65 65 66 66 efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); 67 67 68 + void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid); 69 + 68 70 /* Helper macros for the usual case of using simple C variables: */ 69 71 #ifndef fdt_setprop_inplace_var 70 72 #define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
+9 -18
drivers/firmware/efi/libstub/fdt.c
··· 363 363 364 364 void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size) 365 365 { 366 - efi_guid_t fdt_guid = DEVICE_TREE_GUID; 367 - efi_config_table_t *tables; 368 - int i; 366 + void *fdt; 369 367 370 - tables = (efi_config_table_t *)sys_table->tables; 368 + fdt = get_efi_config_table(sys_table, DEVICE_TREE_GUID); 371 369 372 - for (i = 0; i < sys_table->nr_tables; i++) { 373 - void *fdt; 370 + if (!fdt) 371 + return NULL; 374 372 375 - if (efi_guidcmp(tables[i].guid, fdt_guid) != 0) 376 - continue; 377 - 378 - fdt = (void *)tables[i].table; 379 - if (fdt_check_header(fdt) != 0) { 380 - pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n"); 381 - return NULL; 382 - } 383 - *fdt_size = fdt_totalsize(fdt); 384 - return fdt; 373 + if (fdt_check_header(fdt) != 0) { 374 + pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n"); 375 + return NULL; 385 376 } 386 - 387 - return NULL; 377 + *fdt_size = fdt_totalsize(fdt); 378 + return fdt; 388 379 }
+63 -17
drivers/firmware/efi/libstub/tpm.c
··· 57 57 58 58 #endif 59 59 60 - static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) 60 + void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) 61 61 { 62 62 efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 63 63 efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; 64 64 efi_status_t status; 65 65 efi_physical_addr_t log_location = 0, log_last_entry = 0; 66 66 struct linux_efi_tpm_eventlog *log_tbl = NULL; 67 + struct efi_tcg2_final_events_table *final_events_table; 67 68 unsigned long first_entry_addr, last_entry_addr; 68 69 size_t log_size, last_entry_size; 69 70 efi_bool_t truncated; 71 + int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; 70 72 void *tcg2_protocol = NULL; 73 + int final_events_size = 0; 71 74 72 75 status = efi_call_early(locate_protocol, &tcg2_guid, NULL, 73 76 &tcg2_protocol); 74 77 if (status != EFI_SUCCESS) 75 78 return; 76 79 77 - status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol, 78 - EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, 79 - &log_location, &log_last_entry, &truncated); 80 - if (status != EFI_SUCCESS) 81 - return; 80 + status = efi_call_proto(efi_tcg2_protocol, get_event_log, 81 + tcg2_protocol, version, &log_location, 82 + &log_last_entry, &truncated); 82 83 83 - if (!log_location) 84 - return; 84 + if (status != EFI_SUCCESS || !log_location) { 85 + version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; 86 + status = efi_call_proto(efi_tcg2_protocol, get_event_log, 87 + tcg2_protocol, version, &log_location, 88 + &log_last_entry, &truncated); 89 + if (status != EFI_SUCCESS || !log_location) 90 + return; 91 + 92 + } 93 + 85 94 first_entry_addr = (unsigned long) log_location; 86 95 87 96 /* ··· 105 96 * We need to calculate its size to deduce the full size of 106 97 * the logs. 107 98 */ 108 - last_entry_size = sizeof(struct tcpa_event) + 109 - ((struct tcpa_event *) last_entry_addr)->event_size; 99 + if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { 100 + /* 101 + * The TCG2 log format has variable length entries, 102 + * and the information to decode the hash algorithms 103 + * back into a size is contained in the first entry - 104 + * pass a pointer to the final entry (to calculate its 105 + * size) and the first entry (so we know how long each 106 + * digest is) 107 + */ 108 + last_entry_size = 109 + __calc_tpm2_event_size((void *)last_entry_addr, 110 + (void *)(long)log_location, 111 + false); 112 + } else { 113 + last_entry_size = sizeof(struct tcpa_event) + 114 + ((struct tcpa_event *) last_entry_addr)->event_size; 115 + } 110 116 log_size = log_last_entry - log_location + last_entry_size; 111 117 } 112 118 ··· 136 112 return; 137 113 } 138 114 115 + /* 116 + * Figure out whether any events have already been logged to the 117 + * final events structure, and if so how much space they take up 118 + */ 119 + final_events_table = get_efi_config_table(sys_table_arg, 120 + LINUX_EFI_TPM_FINAL_LOG_GUID); 121 + if (final_events_table && final_events_table->nr_events) { 122 + struct tcg_pcr_event2_head *header; 123 + int offset; 124 + void *data; 125 + int event_size; 126 + int i = final_events_table->nr_events; 127 + 128 + data = (void *)final_events_table; 129 + offset = sizeof(final_events_table->version) + 130 + sizeof(final_events_table->nr_events); 131 + 132 + while (i > 0) { 133 + header = data + offset + final_events_size; 134 + event_size = __calc_tpm2_event_size(header, 135 + (void *)(long)log_location, 136 + false); 137 + final_events_size += event_size; 138 + i--; 139 + } 140 + } 141 + 139 142 memset(log_tbl, 0, sizeof(*log_tbl) + log_size); 140 143 log_tbl->size = log_size; 141 - log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; 144 + log_tbl->final_events_preboot_size = final_events_size; 145 + log_tbl->version = version; 142 146 memcpy(log_tbl->log, (void *) first_entry_addr, log_size); 143 147 144 148 status = efi_call_early(install_configuration_table, ··· 177 125 178 126 err_free: 179 127 efi_call_early(free_pool, log_tbl); 180 - } 181 - 182 - void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) 183 - { 184 - /* Only try to retrieve the logs in 1.2 format. */ 185 - efi_retrieve_tpm2_eventlog_1_2(sys_table_arg); 186 128 }
+59 -4
drivers/firmware/efi/tpm.c
··· 4 4 * Thiebaud Weksteen <tweek@google.com> 5 5 */ 6 6 7 + #define TPM_MEMREMAP(start, size) early_memremap(start, size) 8 + #define TPM_MEMUNMAP(start, size) early_memunmap(start, size) 9 + 10 + #include <asm/early_ioremap.h> 7 11 #include <linux/efi.h> 8 12 #include <linux/init.h> 9 13 #include <linux/memblock.h> 14 + #include <linux/tpm_eventlog.h> 10 15 11 - #include <asm/early_ioremap.h> 16 + int efi_tpm_final_log_size; 17 + EXPORT_SYMBOL(efi_tpm_final_log_size); 18 + 19 + static int tpm2_calc_event_log_size(void *data, int count, void *size_info) 20 + { 21 + struct tcg_pcr_event2_head *header; 22 + int event_size, size = 0; 23 + 24 + while (count > 0) { 25 + header = data + size; 26 + event_size = __calc_tpm2_event_size(header, size_info, true); 27 + if (event_size == 0) 28 + return -1; 29 + size += event_size; 30 + count--; 31 + } 32 + 33 + return size; 34 + } 12 35 13 36 /* 14 37 * Reserve the memory associated with the TPM Event Log configuration table. ··· 39 16 int __init efi_tpm_eventlog_init(void) 40 17 { 41 18 struct linux_efi_tpm_eventlog *log_tbl; 19 + struct efi_tcg2_final_events_table *final_tbl; 42 20 unsigned int tbl_size; 21 + int ret = 0; 43 22 44 - if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) 23 + if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) { 24 + /* 25 + * We can't calculate the size of the final events without the 26 + * first entry in the TPM log, so bail here. 27 + */ 45 28 return 0; 29 + } 46 30 47 31 log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl)); 48 32 if (!log_tbl) { 49 33 pr_err("Failed to map TPM Event Log table @ 0x%lx\n", 50 - efi.tpm_log); 34 + efi.tpm_log); 51 35 efi.tpm_log = EFI_INVALID_TABLE_ADDR; 52 36 return -ENOMEM; 53 37 } 54 38 55 39 tbl_size = sizeof(*log_tbl) + log_tbl->size; 56 40 memblock_reserve(efi.tpm_log, tbl_size); 41 + 42 + if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) 43 + goto out; 44 + 45 + final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl)); 46 + 47 + if (!final_tbl) { 48 + pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n", 49 + efi.tpm_final_log); 50 + efi.tpm_final_log = EFI_INVALID_TABLE_ADDR; 51 + ret = -ENOMEM; 52 + goto out; 53 + } 54 + 55 + tbl_size = tpm2_calc_event_log_size((void *)efi.tpm_final_log 56 + + sizeof(final_tbl->version) 57 + + sizeof(final_tbl->nr_events), 58 + final_tbl->nr_events, 59 + log_tbl->log); 60 + memblock_reserve((unsigned long)final_tbl, 61 + tbl_size + sizeof(*final_tbl)); 62 + early_memunmap(final_tbl, sizeof(*final_tbl)); 63 + efi_tpm_final_log_size = tbl_size; 64 + 65 + out: 57 66 early_memunmap(log_tbl, sizeof(*log_tbl)); 58 - return 0; 67 + return ret; 59 68 } 60 69
+10
include/linux/efi.h
··· 689 689 #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) 690 690 #define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b) 691 691 #define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa) 692 + #define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25) 692 693 #define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2) 693 694 694 695 typedef struct { ··· 997 996 unsigned long mem_attr_table; /* memory attributes table */ 998 997 unsigned long rng_seed; /* UEFI firmware random seed */ 999 998 unsigned long tpm_log; /* TPM2 Event Log table */ 999 + unsigned long tpm_final_log; /* TPM2 Final Events Log table */ 1000 1000 unsigned long mem_reserve; /* Linux EFI memreserve table */ 1001 1001 efi_get_time_t *get_time; 1002 1002 efi_set_time_t *set_time; ··· 1708 1706 1709 1707 struct linux_efi_tpm_eventlog { 1710 1708 u32 size; 1709 + u32 final_events_preboot_size; 1711 1710 u8 version; 1712 1711 u8 log[]; 1713 1712 }; 1714 1713 1715 1714 extern int efi_tpm_eventlog_init(void); 1715 + 1716 + struct efi_tcg2_final_events_table { 1717 + u64 version; 1718 + u64 nr_events; 1719 + u8 events[]; 1720 + }; 1721 + extern int efi_tpm_final_log_size; 1716 1722 1717 1723 /* 1718 1724 * efi_runtime_service() function identifiers.
+152
include/linux/tpm_eventlog.h
··· 112 112 struct tpm_digest digests[]; 113 113 } __packed; 114 114 115 + struct tcg_algorithm_size { 116 + u16 algorithm_id; 117 + u16 algorithm_size; 118 + }; 119 + 120 + struct tcg_algorithm_info { 121 + u8 signature[16]; 122 + u32 platform_class; 123 + u8 spec_version_minor; 124 + u8 spec_version_major; 125 + u8 spec_errata; 126 + u8 uintn_size; 127 + u32 number_of_algorithms; 128 + struct tcg_algorithm_size digest_sizes[]; 129 + }; 130 + 131 + #ifndef TPM_MEMREMAP 132 + #define TPM_MEMREMAP(start, size) NULL 133 + #endif 134 + 135 + #ifndef TPM_MEMUNMAP 136 + #define TPM_MEMUNMAP(start, size) do{} while(0) 137 + #endif 138 + 139 + /** 140 + * __calc_tpm2_event_size - calculate the size of a TPM2 event log entry 141 + * @event: Pointer to the event whose size should be calculated 142 + * @event_header: Pointer to the initial event containing the digest lengths 143 + * @do_mapping: Whether or not the event needs to be mapped 144 + * 145 + * The TPM2 event log format can contain multiple digests corresponding to 146 + * separate PCR banks, and also contains a variable length of the data that 147 + * was measured. This requires knowledge of how long each digest type is, 148 + * and this information is contained within the first event in the log. 149 + * 150 + * We calculate the length by examining the number of events, and then looking 151 + * at each event in turn to determine how much space is used for events in 152 + * total. Once we've done this we know the offset of the data length field, 153 + * and can calculate the total size of the event. 154 + * 155 + * Return: size of the event on success, <0 on failure 156 + */ 157 + 158 + static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event, 159 + struct tcg_pcr_event *event_header, 160 + bool do_mapping) 161 + { 162 + struct tcg_efi_specid_event_head *efispecid; 163 + struct tcg_event_field *event_field; 164 + void *mapping = NULL; 165 + int mapping_size; 166 + void *marker; 167 + void *marker_start; 168 + u32 halg_size; 169 + size_t size; 170 + u16 halg; 171 + int i; 172 + int j; 173 + 174 + marker = event; 175 + marker_start = marker; 176 + marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) 177 + + sizeof(event->count); 178 + 179 + /* Map the event header */ 180 + if (do_mapping) { 181 + mapping_size = marker - marker_start; 182 + mapping = TPM_MEMREMAP((unsigned long)marker_start, 183 + mapping_size); 184 + if (!mapping) { 185 + size = 0; 186 + goto out; 187 + } 188 + } else { 189 + mapping = marker_start; 190 + } 191 + 192 + event = (struct tcg_pcr_event2_head *)mapping; 193 + 194 + efispecid = (struct tcg_efi_specid_event_head *)event_header->event; 195 + 196 + /* Check if event is malformed. */ 197 + if (event->count > efispecid->num_algs) { 198 + size = 0; 199 + goto out; 200 + } 201 + 202 + for (i = 0; i < event->count; i++) { 203 + halg_size = sizeof(event->digests[i].alg_id); 204 + 205 + /* Map the digest's algorithm identifier */ 206 + if (do_mapping) { 207 + TPM_MEMUNMAP(mapping, mapping_size); 208 + mapping_size = halg_size; 209 + mapping = TPM_MEMREMAP((unsigned long)marker, 210 + mapping_size); 211 + if (!mapping) { 212 + size = 0; 213 + goto out; 214 + } 215 + } else { 216 + mapping = marker; 217 + } 218 + 219 + memcpy(&halg, mapping, halg_size); 220 + marker = marker + halg_size; 221 + 222 + for (j = 0; j < efispecid->num_algs; j++) { 223 + if (halg == efispecid->digest_sizes[j].alg_id) { 224 + marker += 225 + efispecid->digest_sizes[j].digest_size; 226 + break; 227 + } 228 + } 229 + /* Algorithm without known length. Such event is unparseable. */ 230 + if (j == efispecid->num_algs) { 231 + size = 0; 232 + goto out; 233 + } 234 + } 235 + 236 + /* 237 + * Map the event size - we don't read from the event itself, so 238 + * we don't need to map it 239 + */ 240 + if (do_mapping) { 241 + TPM_MEMUNMAP(mapping, mapping_size); 242 + mapping_size += sizeof(event_field->event_size); 243 + mapping = TPM_MEMREMAP((unsigned long)marker, 244 + mapping_size); 245 + if (!mapping) { 246 + size = 0; 247 + goto out; 248 + } 249 + } else { 250 + mapping = marker; 251 + } 252 + 253 + event_field = (struct tcg_event_field *)mapping; 254 + 255 + marker = marker + sizeof(event_field->event_size) 256 + + event_field->event_size; 257 + size = marker - marker_start; 258 + 259 + if ((event->event_type == 0) && (event_field->event_size == 0)) 260 + size = 0; 261 + out: 262 + if (do_mapping) 263 + TPM_MEMUNMAP(mapping, mapping_size); 264 + return size; 265 + } 266 + 115 267 #endif