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 #include <linux/tpm_eventlog.h> 25 26 #include "../tpm.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 /* Check if event is malformed. */ 60 if (event->count > efispecid->num_algs) 61 return 0; 62 63 for (i = 0; i < event->count; i++) { 64 halg_size = sizeof(event->digests[i].alg_id); 65 memcpy(&halg, marker, halg_size); 66 marker = marker + halg_size; 67 for (j = 0; j < efispecid->num_algs; j++) { 68 if (halg == efispecid->digest_sizes[j].alg_id) { 69 marker += 70 efispecid->digest_sizes[j].digest_size; 71 break; 72 } 73 } 74 /* Algorithm without known length. Such event is unparseable. */ 75 if (j == efispecid->num_algs) 76 return 0; 77 } 78 79 event_field = (struct tcg_event_field *)marker; 80 marker = marker + sizeof(event_field->event_size) 81 + event_field->event_size; 82 size = marker - marker_start; 83 84 if ((event->event_type == 0) && (event_field->event_size == 0)) 85 return 0; 86 87 return size; 88 } 89 90 static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) 91 { 92 struct tpm_chip *chip = m->private; 93 struct tpm_bios_log *log = &chip->log; 94 void *addr = log->bios_event_log; 95 void *limit = log->bios_event_log_end; 96 struct tcg_pcr_event *event_header; 97 struct tcg_pcr_event2 *event; 98 size_t size; 99 int i; 100 101 event_header = addr; 102 size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) 103 + event_header->event_size; 104 105 if (*pos == 0) { 106 if (addr + size < limit) { 107 if ((event_header->event_type == 0) && 108 (event_header->event_size == 0)) 109 return NULL; 110 return SEQ_START_TOKEN; 111 } 112 } 113 114 if (*pos > 0) { 115 addr += size; 116 event = addr; 117 size = calc_tpm2_event_size(event, event_header); 118 if ((addr + size >= limit) || (size == 0)) 119 return NULL; 120 } 121 122 for (i = 0; i < (*pos - 1); i++) { 123 event = addr; 124 size = calc_tpm2_event_size(event, event_header); 125 126 if ((addr + size >= limit) || (size == 0)) 127 return NULL; 128 addr += size; 129 } 130 131 return addr; 132 } 133 134 static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, 135 loff_t *pos) 136 { 137 struct tcg_pcr_event *event_header; 138 struct tcg_pcr_event2 *event; 139 struct tpm_chip *chip = m->private; 140 struct tpm_bios_log *log = &chip->log; 141 void *limit = log->bios_event_log_end; 142 size_t event_size; 143 void *marker; 144 145 event_header = log->bios_event_log; 146 147 if (v == SEQ_START_TOKEN) { 148 event_size = sizeof(struct tcg_pcr_event) - 149 sizeof(event_header->event) + event_header->event_size; 150 marker = event_header; 151 } else { 152 event = v; 153 event_size = calc_tpm2_event_size(event, event_header); 154 if (event_size == 0) 155 return NULL; 156 marker = event; 157 } 158 159 marker = marker + event_size; 160 if (marker >= limit) 161 return NULL; 162 v = marker; 163 event = v; 164 165 event_size = calc_tpm2_event_size(event, event_header); 166 if (((v + event_size) >= limit) || (event_size == 0)) 167 return NULL; 168 169 (*pos)++; 170 return v; 171 } 172 173 static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) 174 { 175 } 176 177 static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) 178 { 179 struct tpm_chip *chip = m->private; 180 struct tpm_bios_log *log = &chip->log; 181 struct tcg_pcr_event *event_header = log->bios_event_log; 182 struct tcg_pcr_event2 *event = v; 183 void *temp_ptr; 184 size_t size; 185 186 if (v == SEQ_START_TOKEN) { 187 size = sizeof(struct tcg_pcr_event) - 188 sizeof(event_header->event) + event_header->event_size; 189 190 temp_ptr = event_header; 191 192 if (size > 0) 193 seq_write(m, temp_ptr, size); 194 } else { 195 size = calc_tpm2_event_size(event, event_header); 196 temp_ptr = event; 197 if (size > 0) 198 seq_write(m, temp_ptr, size); 199 } 200 201 return 0; 202 } 203 204 const struct seq_operations tpm2_binary_b_measurements_seqops = { 205 .start = tpm2_bios_measurements_start, 206 .next = tpm2_bios_measurements_next, 207 .stop = tpm2_bios_measurements_stop, 208 .show = tpm2_binary_bios_measurements_show, 209 }; 210