summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 21:47:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 21:47:42 -0400
commit884922591e2b58fd7f1018701f957446d1ffac4d (patch)
tree173877a1a82a68678a1655ec4d105c7cb16e3303
parent222a21d29521d144f3dd7a0bc4d4020e448f0126 (diff)
parent166a2809d65b282272c474835ec22c882a39ca1b (diff)
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"
-rw-r--r--drivers/char/tpm/eventlog/efi.c59
-rw-r--r--drivers/char/tpm/eventlog/tpm2.c47
-rw-r--r--drivers/char/tpm/tpm-chip.c6
-rw-r--r--drivers/char/tpm/tpm1-cmd.c7
-rw-r--r--drivers/char/tpm/tpm2-cmd.c7
-rw-r--r--drivers/firmware/efi/efi.c2
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c15
-rw-r--r--drivers/firmware/efi/libstub/efistub.h2
-rw-r--r--drivers/firmware/efi/libstub/fdt.c27
-rw-r--r--drivers/firmware/efi/libstub/tpm.c80
-rw-r--r--drivers/firmware/efi/tpm.c63
-rw-r--r--include/linux/efi.h10
-rw-r--r--include/linux/tpm_eventlog.h152
13 files changed, 378 insertions, 99 deletions
diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c
index 3e44362e469c..6bb023de17f1 100644
--- a/drivers/char/tpm/eventlog/efi.c
+++ b/drivers/char/tpm/eventlog/efi.c
@@ -16,10 +16,13 @@
16int tpm_read_log_efi(struct tpm_chip *chip) 16int tpm_read_log_efi(struct tpm_chip *chip)
17{ 17{
18 18
19 struct efi_tcg2_final_events_table *final_tbl = NULL;
19 struct linux_efi_tpm_eventlog *log_tbl; 20 struct linux_efi_tpm_eventlog *log_tbl;
20 struct tpm_bios_log *log; 21 struct tpm_bios_log *log;
21 u32 log_size; 22 u32 log_size;
22 u8 tpm_log_version; 23 u8 tpm_log_version;
24 void *tmp;
25 int ret;
23 26
24 if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) 27 if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
25 return -ENODEV; 28 return -ENODEV;
@@ -47,15 +50,57 @@ int tpm_read_log_efi(struct tpm_chip *chip)
47 50
48 /* malloc EventLog space */ 51 /* malloc EventLog space */
49 log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL); 52 log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
50 if (!log->bios_event_log) 53 if (!log->bios_event_log) {
51 goto err_memunmap; 54 ret = -ENOMEM;
52 log->bios_event_log_end = log->bios_event_log + log_size; 55 goto out;
56 }
53 57
58 log->bios_event_log_end = log->bios_event_log + log_size;
54 tpm_log_version = log_tbl->version; 59 tpm_log_version = log_tbl->version;
55 memunmap(log_tbl);
56 return tpm_log_version;
57 60
58err_memunmap: 61 ret = tpm_log_version;
62
63 if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
64 efi_tpm_final_log_size == 0 ||
65 tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
66 goto out;
67
68 final_tbl = memremap(efi.tpm_final_log,
69 sizeof(*final_tbl) + efi_tpm_final_log_size,
70 MEMREMAP_WB);
71 if (!final_tbl) {
72 pr_err("Could not map UEFI TPM final log\n");
73 kfree(log->bios_event_log);
74 ret = -ENOMEM;
75 goto out;
76 }
77
78 efi_tpm_final_log_size -= log_tbl->final_events_preboot_size;
79
80 tmp = krealloc(log->bios_event_log,
81 log_size + efi_tpm_final_log_size,
82 GFP_KERNEL);
83 if (!tmp) {
84 kfree(log->bios_event_log);
85 ret = -ENOMEM;
86 goto out;
87 }
88
89 log->bios_event_log = tmp;
90
91 /*
92 * Copy any of the final events log that didn't also end up in the
93 * main log. Events can be logged in both if events are generated
94 * between GetEventLog() and ExitBootServices().
95 */
96 memcpy((void *)log->bios_event_log + log_size,
97 final_tbl->events + log_tbl->final_events_preboot_size,
98 efi_tpm_final_log_size);
99 log->bios_event_log_end = log->bios_event_log +
100 log_size + efi_tpm_final_log_size;
101
102out:
103 memunmap(final_tbl);
59 memunmap(log_tbl); 104 memunmap(log_tbl);
60 return -ENOMEM; 105 return ret;
61} 106}
diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
index d506362e046f..b9aeda1cbcd7 100644
--- a/drivers/char/tpm/eventlog/tpm2.c
+++ b/drivers/char/tpm/eventlog/tpm2.c
@@ -36,52 +36,7 @@
36static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, 36static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
37 struct tcg_pcr_event *event_header) 37 struct tcg_pcr_event *event_header)
38{ 38{
39 struct tcg_efi_specid_event_head *efispecid; 39 return __calc_tpm2_event_size(event, event_header, false);
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;
85} 40}
86 41
87static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) 42static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 90325e1749fb..d47ad10a35fe 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -289,15 +289,15 @@ static int tpm_class_shutdown(struct device *dev)
289{ 289{
290 struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); 290 struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
291 291
292 down_write(&chip->ops_sem);
292 if (chip->flags & TPM_CHIP_FLAG_TPM2) { 293 if (chip->flags & TPM_CHIP_FLAG_TPM2) {
293 down_write(&chip->ops_sem);
294 if (!tpm_chip_start(chip)) { 294 if (!tpm_chip_start(chip)) {
295 tpm2_shutdown(chip, TPM2_SU_CLEAR); 295 tpm2_shutdown(chip, TPM2_SU_CLEAR);
296 tpm_chip_stop(chip); 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 return 0; 302 return 0;
303} 303}
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index 85dcf2654d11..faacbe1ffa1a 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -510,7 +510,7 @@ struct tpm1_get_random_out {
510 * 510 *
511 * Return: 511 * Return:
512 * * number of bytes read 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 */
515int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) 515int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
516{ 516{
@@ -531,8 +531,11 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
531 531
532 rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len), 532 rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
533 "attempting get random"); 533 "attempting get random");
534 if (rc) 534 if (rc) {
535 if (rc > 0)
536 rc = -EIO;
535 goto out; 537 goto out;
538 }
536 539
537 out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE]; 540 out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
538 541
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 4de49924cfc4..d103545e4055 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -297,7 +297,7 @@ struct tpm2_get_random_out {
297 * 297 *
298 * Return: 298 * Return:
299 * size of the buffer on success, 299 * size of the buffer on success,
300 * -errno otherwise 300 * -errno otherwise (positive TPM return codes are masked to -EIO)
301 */ 301 */
302int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) 302int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
303{ 303{
@@ -324,8 +324,11 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
324 offsetof(struct tpm2_get_random_out, 324 offsetof(struct tpm2_get_random_out,
325 buffer), 325 buffer),
326 "attempting get random"); 326 "attempting get random");
327 if (err) 327 if (err) {
328 if (err > 0)
329 err = -EIO;
328 goto out; 330 goto out;
331 }
329 332
330 out = (struct tpm2_get_random_out *) 333 out = (struct tpm2_get_random_out *)
331 &buf.data[TPM_HEADER_SIZE]; 334 &buf.data[TPM_HEADER_SIZE];
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 4b7cf7bc0ded..ad3b1f4866b3 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -52,6 +52,7 @@ struct efi __read_mostly efi = {
52 .mem_attr_table = EFI_INVALID_TABLE_ADDR, 52 .mem_attr_table = EFI_INVALID_TABLE_ADDR,
53 .rng_seed = EFI_INVALID_TABLE_ADDR, 53 .rng_seed = EFI_INVALID_TABLE_ADDR,
54 .tpm_log = EFI_INVALID_TABLE_ADDR, 54 .tpm_log = EFI_INVALID_TABLE_ADDR,
55 .tpm_final_log = EFI_INVALID_TABLE_ADDR,
55 .mem_reserve = EFI_INVALID_TABLE_ADDR, 56 .mem_reserve = EFI_INVALID_TABLE_ADDR,
56}; 57};
57EXPORT_SYMBOL(efi); 58EXPORT_SYMBOL(efi);
@@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
484 {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table}, 485 {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
485 {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed}, 486 {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
486 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, 487 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
488 {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
487 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, 489 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
488 {NULL_GUID, NULL, NULL}, 490 {NULL_GUID, NULL, NULL},
489}; 491};
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index e4610e72b78f..1db780c0f07b 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -926,3 +926,18 @@ free_map:
926fail: 926fail:
927 return status; 927 return status;
928} 928}
929
930void *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}
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 1b1dfcaa6fb9..7f1556fd867d 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -65,6 +65,8 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg);
65 65
66efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); 66efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg);
67 67
68void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid);
69
68/* Helper macros for the usual case of using simple C variables: */ 70/* Helper macros for the usual case of using simple C variables: */
69#ifndef fdt_setprop_inplace_var 71#ifndef fdt_setprop_inplace_var
70#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \ 72#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index 5440ba17a1c5..0bf0190917e0 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -363,26 +363,17 @@ fail:
363 363
364void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size) 364void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size)
365{ 365{
366 efi_guid_t fdt_guid = DEVICE_TREE_GUID; 366 void *fdt;
367 efi_config_table_t *tables;
368 int i;
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++) { 370 if (!fdt)
373 void *fdt; 371 return NULL;
374 372
375 if (efi_guidcmp(tables[i].guid, fdt_guid) != 0) 373 if (fdt_check_header(fdt) != 0) {
376 continue; 374 pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n");
377 375 return NULL;
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;
385 } 376 }
386 377 *fdt_size = fdt_totalsize(fdt);
387 return NULL; 378 return fdt;
388} 379}
diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c
index 5bd04f75d8d6..eb9af83e4d59 100644
--- a/drivers/firmware/efi/libstub/tpm.c
+++ b/drivers/firmware/efi/libstub/tpm.c
@@ -57,31 +57,40 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
57 57
58#endif 58#endif
59 59
60static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) 60void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
61{ 61{
62 efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 62 efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
63 efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; 63 efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
64 efi_status_t status; 64 efi_status_t status;
65 efi_physical_addr_t log_location = 0, log_last_entry = 0; 65 efi_physical_addr_t log_location = 0, log_last_entry = 0;
66 struct linux_efi_tpm_eventlog *log_tbl = NULL; 66 struct linux_efi_tpm_eventlog *log_tbl = NULL;
67 struct efi_tcg2_final_events_table *final_events_table;
67 unsigned long first_entry_addr, last_entry_addr; 68 unsigned long first_entry_addr, last_entry_addr;
68 size_t log_size, last_entry_size; 69 size_t log_size, last_entry_size;
69 efi_bool_t truncated; 70 efi_bool_t truncated;
71 int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
70 void *tcg2_protocol = NULL; 72 void *tcg2_protocol = NULL;
73 int final_events_size = 0;
71 74
72 status = efi_call_early(locate_protocol, &tcg2_guid, NULL, 75 status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
73 &tcg2_protocol); 76 &tcg2_protocol);
74 if (status != EFI_SUCCESS) 77 if (status != EFI_SUCCESS)
75 return; 78 return;
76 79
77 status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol, 80 status = efi_call_proto(efi_tcg2_protocol, get_event_log,
78 EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, 81 tcg2_protocol, version, &log_location,
79 &log_location, &log_last_entry, &truncated); 82 &log_last_entry, &truncated);
80 if (status != EFI_SUCCESS) 83
81 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 }
82 93
83 if (!log_location)
84 return;
85 first_entry_addr = (unsigned long) log_location; 94 first_entry_addr = (unsigned long) log_location;
86 95
87 /* 96 /*
@@ -96,8 +105,23 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
96 * We need to calculate its size to deduce the full size of 105 * We need to calculate its size to deduce the full size of
97 * the logs. 106 * the logs.
98 */ 107 */
99 last_entry_size = sizeof(struct tcpa_event) + 108 if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
100 ((struct tcpa_event *) last_entry_addr)->event_size; 109 /*
110 * The TCG2 log format has variable length entries,
111 * and the information to decode the hash algorithms
112 * back into a size is contained in the first entry -
113 * pass a pointer to the final entry (to calculate its
114 * size) and the first entry (so we know how long each
115 * digest is)
116 */
117 last_entry_size =
118 __calc_tpm2_event_size((void *)last_entry_addr,
119 (void *)(long)log_location,
120 false);
121 } else {
122 last_entry_size = sizeof(struct tcpa_event) +
123 ((struct tcpa_event *) last_entry_addr)->event_size;
124 }
101 log_size = log_last_entry - log_location + last_entry_size; 125 log_size = log_last_entry - log_location + last_entry_size;
102 } 126 }
103 127
@@ -112,9 +136,37 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
112 return; 136 return;
113 } 137 }
114 138
139 /*
140 * Figure out whether any events have already been logged to the
141 * final events structure, and if so how much space they take up
142 */
143 final_events_table = get_efi_config_table(sys_table_arg,
144 LINUX_EFI_TPM_FINAL_LOG_GUID);
145 if (final_events_table && final_events_table->nr_events) {
146 struct tcg_pcr_event2_head *header;
147 int offset;
148 void *data;
149 int event_size;
150 int i = final_events_table->nr_events;
151
152 data = (void *)final_events_table;
153 offset = sizeof(final_events_table->version) +
154 sizeof(final_events_table->nr_events);
155
156 while (i > 0) {
157 header = data + offset + final_events_size;
158 event_size = __calc_tpm2_event_size(header,
159 (void *)(long)log_location,
160 false);
161 final_events_size += event_size;
162 i--;
163 }
164 }
165
115 memset(log_tbl, 0, sizeof(*log_tbl) + log_size); 166 memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
116 log_tbl->size = log_size; 167 log_tbl->size = log_size;
117 log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; 168 log_tbl->final_events_preboot_size = final_events_size;
169 log_tbl->version = version;
118 memcpy(log_tbl->log, (void *) first_entry_addr, log_size); 170 memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
119 171
120 status = efi_call_early(install_configuration_table, 172 status = efi_call_early(install_configuration_table,
@@ -126,9 +178,3 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
126err_free: 178err_free:
127 efi_call_early(free_pool, log_tbl); 179 efi_call_early(free_pool, log_tbl);
128} 180}
129
130void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
131{
132 /* Only try to retrieve the logs in 1.2 format. */
133 efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
134}
diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c
index 3a689b40ccc0..1d3f5ca3eaaf 100644
--- a/drivers/firmware/efi/tpm.c
+++ b/drivers/firmware/efi/tpm.c
@@ -4,11 +4,34 @@
4 * Thiebaud Weksteen <tweek@google.com> 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#include <linux/efi.h> 11#include <linux/efi.h>
8#include <linux/init.h> 12#include <linux/init.h>
9#include <linux/memblock.h> 13#include <linux/memblock.h>
14#include <linux/tpm_eventlog.h>
10 15
11#include <asm/early_ioremap.h> 16int efi_tpm_final_log_size;
17EXPORT_SYMBOL(efi_tpm_final_log_size);
18
19static 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 * Reserve the memory associated with the TPM Event Log configuration table. 37 * Reserve the memory associated with the TPM Event Log configuration table.
@@ -16,22 +39,54 @@
16int __init efi_tpm_eventlog_init(void) 39int __init efi_tpm_eventlog_init(void)
17{ 40{
18 struct linux_efi_tpm_eventlog *log_tbl; 41 struct linux_efi_tpm_eventlog *log_tbl;
42 struct efi_tcg2_final_events_table *final_tbl;
19 unsigned int tbl_size; 43 unsigned int tbl_size;
44 int ret = 0;
20 45
21 if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) 46 if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) {
47 /*
48 * We can't calculate the size of the final events without the
49 * first entry in the TPM log, so bail here.
50 */
22 return 0; 51 return 0;
52 }
23 53
24 log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl)); 54 log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
25 if (!log_tbl) { 55 if (!log_tbl) {
26 pr_err("Failed to map TPM Event Log table @ 0x%lx\n", 56 pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
27 efi.tpm_log); 57 efi.tpm_log);
28 efi.tpm_log = EFI_INVALID_TABLE_ADDR; 58 efi.tpm_log = EFI_INVALID_TABLE_ADDR;
29 return -ENOMEM; 59 return -ENOMEM;
30 } 60 }
31 61
32 tbl_size = sizeof(*log_tbl) + log_tbl->size; 62 tbl_size = sizeof(*log_tbl) + log_tbl->size;
33 memblock_reserve(efi.tpm_log, tbl_size); 63 memblock_reserve(efi.tpm_log, tbl_size);
64
65 if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR)
66 goto out;
67
68 final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl));
69
70 if (!final_tbl) {
71 pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n",
72 efi.tpm_final_log);
73 efi.tpm_final_log = EFI_INVALID_TABLE_ADDR;
74 ret = -ENOMEM;
75 goto out;
76 }
77
78 tbl_size = tpm2_calc_event_log_size((void *)efi.tpm_final_log
79 + sizeof(final_tbl->version)
80 + sizeof(final_tbl->nr_events),
81 final_tbl->nr_events,
82 log_tbl->log);
83 memblock_reserve((unsigned long)final_tbl,
84 tbl_size + sizeof(*final_tbl));
85 early_memunmap(final_tbl, sizeof(*final_tbl));
86 efi_tpm_final_log_size = tbl_size;
87
88out:
34 early_memunmap(log_tbl, sizeof(*log_tbl)); 89 early_memunmap(log_tbl, sizeof(*log_tbl));
35 return 0; 90 return ret;
36} 91}
37 92
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 6ebc2098cfe1..f87fabea4a85 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -689,6 +689,7 @@ void efi_native_runtime_setup(void);
689#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) 689#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
690#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b) 690#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
691#define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa) 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#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2) 693#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
693 694
694typedef struct { 695typedef struct {
@@ -996,6 +997,7 @@ extern struct efi {
996 unsigned long mem_attr_table; /* memory attributes table */ 997 unsigned long mem_attr_table; /* memory attributes table */
997 unsigned long rng_seed; /* UEFI firmware random seed */ 998 unsigned long rng_seed; /* UEFI firmware random seed */
998 unsigned long tpm_log; /* TPM2 Event Log table */ 999 unsigned long tpm_log; /* TPM2 Event Log table */
1000 unsigned long tpm_final_log; /* TPM2 Final Events Log table */
999 unsigned long mem_reserve; /* Linux EFI memreserve table */ 1001 unsigned long mem_reserve; /* Linux EFI memreserve table */
1000 efi_get_time_t *get_time; 1002 efi_get_time_t *get_time;
1001 efi_set_time_t *set_time; 1003 efi_set_time_t *set_time;
@@ -1706,12 +1708,20 @@ struct linux_efi_random_seed {
1706 1708
1707struct linux_efi_tpm_eventlog { 1709struct linux_efi_tpm_eventlog {
1708 u32 size; 1710 u32 size;
1711 u32 final_events_preboot_size;
1709 u8 version; 1712 u8 version;
1710 u8 log[]; 1713 u8 log[];
1711}; 1714};
1712 1715
1713extern int efi_tpm_eventlog_init(void); 1716extern int efi_tpm_eventlog_init(void);
1714 1717
1718struct efi_tcg2_final_events_table {
1719 u64 version;
1720 u64 nr_events;
1721 u8 events[];
1722};
1723extern int efi_tpm_final_log_size;
1724
1715/* 1725/*
1716 * efi_runtime_service() function identifiers. 1726 * efi_runtime_service() function identifiers.
1717 * "NONE" is used by efi_recover_from_page_fault() to check if the page 1727 * "NONE" is used by efi_recover_from_page_fault() to check if the page
diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
index 81519f163211..63238c84dc0b 100644
--- a/include/linux/tpm_eventlog.h
+++ b/include/linux/tpm_eventlog.h
@@ -112,4 +112,156 @@ struct tcg_pcr_event2_head {
112 struct tpm_digest digests[]; 112 struct tpm_digest digests[];
113} __packed; 113} __packed;
114 114
115struct tcg_algorithm_size {
116 u16 algorithm_id;
117 u16 algorithm_size;
118};
119
120struct 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
158static 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;
261out:
262 if (do_mapping)
263 TPM_MEMUNMAP(mapping, mapping_size);
264 return size;
265}
266
115#endif 267#endif