1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2016 IBM Corporation 4 * 5 * Authors: 6 * Nayna Jain <nayna@linux.vnet.ibm.com> 7 * 8 * Access to TPM 2.0 event log as written by Firmware. 9 * It assumes that writer of event log has followed TCG Specification 10 * for Family "2.0" and written the event data in little endian. 11 * With that, it doesn't need any endian conversion for structure 12 * content. 13 */ 14 15 #include <linux/seq_file.h> 16 #include <linux/fs.h> 17 #include <linux/security.h> 18 #include <linux/module.h> 19 #include <linux/slab.h> 20 #include <linux/tpm_eventlog.h> 21 22 #include "../tpm.h" 23 #include "common.h" 24 25 /* 26 * calc_tpm2_event_size() - calculate the event size, where event 27 * is an entry in the TPM 2.0 event log. The event is of type Crypto 28 * Agile Log Entry Format as defined in TCG EFI Protocol Specification 29 * Family "2.0". 30 31 * @event: event whose size is to be calculated. 32 * @event_header: the first event in the event log. 33 * 34 * Returns size of the event. If it is an invalid event, returns 0. 35 */ 36 static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, 37 struct tcg_pcr_event *event_header) 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; 85 } 86 87 static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) 88 { 89 struct tpm_chip *chip = m->private; 90 struct tpm_bios_log *log = &chip->log; 91 void *addr = log->bios_event_log; 92 void *limit = log->bios_event_log_end; 93 struct tcg_pcr_event *event_header; 94 struct tcg_pcr_event2_head *event; 95 size_t size; 96 int i; 97 98 event_header = addr; 99 size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) 100 + event_header->event_size; 101 102 if (*pos == 0) { 103 if (addr + size < limit) { 104 if ((event_header->event_type == 0) && 105 (event_header->event_size == 0)) 106 return NULL; 107 return SEQ_START_TOKEN; 108 } 109 } 110 111 if (*pos > 0) { 112 addr += size; 113 event = addr; 114 size = calc_tpm2_event_size(event, event_header); 115 if ((addr + size >= limit) || (size == 0)) 116 return NULL; 117 } 118 119 for (i = 0; i < (*pos - 1); i++) { 120 event = addr; 121 size = calc_tpm2_event_size(event, event_header); 122 123 if ((addr + size >= limit) || (size == 0)) 124 return NULL; 125 addr += size; 126 } 127 128 return addr; 129 } 130 131 static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, 132 loff_t *pos) 133 { 134 struct tcg_pcr_event *event_header; 135 struct tcg_pcr_event2_head *event; 136 struct tpm_chip *chip = m->private; 137 struct tpm_bios_log *log = &chip->log; 138 void *limit = log->bios_event_log_end; 139 size_t event_size; 140 void *marker; 141 142 event_header = log->bios_event_log; 143 144 if (v == SEQ_START_TOKEN) { 145 event_size = sizeof(struct tcg_pcr_event) - 146 sizeof(event_header->event) + event_header->event_size; 147 marker = event_header; 148 } else { 149 event = v; 150 event_size = calc_tpm2_event_size(event, event_header); 151 if (event_size == 0) 152 return NULL; 153 marker = event; 154 } 155 156 marker = marker + event_size; 157 if (marker >= limit) 158 return NULL; 159 v = marker; 160 event = v; 161 162 event_size = calc_tpm2_event_size(event, event_header); 163 if (((v + event_size) >= limit) || (event_size == 0)) 164 return NULL; 165 166 (*pos)++; 167 return v; 168 } 169 170 static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) 171 { 172 } 173 174 static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) 175 { 176 struct tpm_chip *chip = m->private; 177 struct tpm_bios_log *log = &chip->log; 178 struct tcg_pcr_event *event_header = log->bios_event_log; 179 struct tcg_pcr_event2_head *event = v; 180 void *temp_ptr; 181 size_t size; 182 183 if (v == SEQ_START_TOKEN) { 184 size = sizeof(struct tcg_pcr_event) - 185 sizeof(event_header->event) + event_header->event_size; 186 187 temp_ptr = event_header; 188 189 if (size > 0) 190 seq_write(m, temp_ptr, size); 191 } else { 192 size = calc_tpm2_event_size(event, event_header); 193 temp_ptr = event; 194 if (size > 0) 195 seq_write(m, temp_ptr, size); 196 } 197 198 return 0; 199 } 200 201 const struct seq_operations tpm2_binary_b_measurements_seqops = { 202 .start = tpm2_bios_measurements_start, 203 .next = tpm2_bios_measurements_next, 204 .stop = tpm2_bios_measurements_stop, 205 .show = tpm2_binary_bios_measurements_show, 206 }; 207