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 #include "common.h" 28 29 /* 30 * calc_tpm2_event_size() - calculate the event size, where event 31 * is an entry in the TPM 2.0 event log. The event is of type Crypto 32 * Agile Log Entry Format as defined in TCG EFI Protocol Specification 33 * Family "2.0". 34 35 * @event: event whose size is to be calculated. 36 * @event_header: the first event in the event log. 37 * 38 * Returns size of the event. If it is an invalid event, returns 0. 39 */ 40 static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, 41 struct tcg_pcr_event *event_header) 42 { 43 struct tcg_efi_specid_event *efispecid; 44 struct tcg_event_field *event_field; 45 void *marker; 46 void *marker_start; 47 u32 halg_size; 48 size_t size; 49 u16 halg; 50 int i; 51 int j; 52 53 marker = event; 54 marker_start = marker; 55 marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) 56 + sizeof(event->count); 57 58 efispecid = (struct tcg_efi_specid_event *)event_header->event; 59 60 /* Check if event is malformed. */ 61 if (event->count > efispecid->num_algs) 62 return 0; 63 64 for (i = 0; i < event->count; i++) { 65 halg_size = sizeof(event->digests[i].alg_id); 66 memcpy(&halg, marker, halg_size); 67 marker = marker + halg_size; 68 for (j = 0; j < efispecid->num_algs; j++) { 69 if (halg == efispecid->digest_sizes[j].alg_id) { 70 marker += 71 efispecid->digest_sizes[j].digest_size; 72 break; 73 } 74 } 75 /* Algorithm without known length. Such event is unparseable. */ 76 if (j == efispecid->num_algs) 77 return 0; 78 } 79 80 event_field = (struct tcg_event_field *)marker; 81 marker = marker + sizeof(event_field->event_size) 82 + event_field->event_size; 83 size = marker - marker_start; 84 85 if ((event->event_type == 0) && (event_field->event_size == 0)) 86 return 0; 87 88 return size; 89 } 90 91 static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) 92 { 93 struct tpm_chip *chip = m->private; 94 struct tpm_bios_log *log = &chip->log; 95 void *addr = log->bios_event_log; 96 void *limit = log->bios_event_log_end; 97 struct tcg_pcr_event *event_header; 98 struct tcg_pcr_event2 *event; 99 size_t size; 100 int i; 101 102 event_header = addr; 103 size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event) 104 + event_header->event_size; 105 106 if (*pos == 0) { 107 if (addr + size < limit) { 108 if ((event_header->event_type == 0) && 109 (event_header->event_size == 0)) 110 return NULL; 111 return SEQ_START_TOKEN; 112 } 113 } 114 115 if (*pos > 0) { 116 addr += size; 117 event = addr; 118 size = calc_tpm2_event_size(event, event_header); 119 if ((addr + size >= limit) || (size == 0)) 120 return NULL; 121 } 122 123 for (i = 0; i < (*pos - 1); i++) { 124 event = addr; 125 size = calc_tpm2_event_size(event, event_header); 126 127 if ((addr + size >= limit) || (size == 0)) 128 return NULL; 129 addr += size; 130 } 131 132 return addr; 133 } 134 135 static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, 136 loff_t *pos) 137 { 138 struct tcg_pcr_event *event_header; 139 struct tcg_pcr_event2 *event; 140 struct tpm_chip *chip = m->private; 141 struct tpm_bios_log *log = &chip->log; 142 void *limit = log->bios_event_log_end; 143 size_t event_size; 144 void *marker; 145 146 event_header = log->bios_event_log; 147 148 if (v == SEQ_START_TOKEN) { 149 event_size = sizeof(struct tcg_pcr_event) - 150 sizeof(event_header->event) + event_header->event_size; 151 marker = event_header; 152 } else { 153 event = v; 154 event_size = calc_tpm2_event_size(event, event_header); 155 if (event_size == 0) 156 return NULL; 157 marker = event; 158 } 159 160 marker = marker + event_size; 161 if (marker >= limit) 162 return NULL; 163 v = marker; 164 event = v; 165 166 event_size = calc_tpm2_event_size(event, event_header); 167 if (((v + event_size) >= limit) || (event_size == 0)) 168 return NULL; 169 170 (*pos)++; 171 return v; 172 } 173 174 static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) 175 { 176 } 177 178 static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) 179 { 180 struct tpm_chip *chip = m->private; 181 struct tpm_bios_log *log = &chip->log; 182 struct tcg_pcr_event *event_header = log->bios_event_log; 183 struct tcg_pcr_event2 *event = v; 184 void *temp_ptr; 185 size_t size; 186 187 if (v == SEQ_START_TOKEN) { 188 size = sizeof(struct tcg_pcr_event) - 189 sizeof(event_header->event) + event_header->event_size; 190 191 temp_ptr = event_header; 192 193 if (size > 0) 194 seq_write(m, temp_ptr, size); 195 } else { 196 size = calc_tpm2_event_size(event, event_header); 197 temp_ptr = event; 198 if (size > 0) 199 seq_write(m, temp_ptr, size); 200 } 201 202 return 0; 203 } 204 205 const struct seq_operations tpm2_binary_b_measurements_seqops = { 206 .start = tpm2_bios_measurements_start, 207 .next = tpm2_bios_measurements_next, 208 .stop = tpm2_bios_measurements_stop, 209 .show = tpm2_binary_bios_measurements_show, 210 }; 211