1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2005, 2012 IBM Corporation
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Authors:
6*4882a593Smuzhiyun * Kent Yoder <key@linux.vnet.ibm.com>
7*4882a593Smuzhiyun * Seiji Munetoh <munetoh@jp.ibm.com>
8*4882a593Smuzhiyun * Stefan Berger <stefanb@us.ibm.com>
9*4882a593Smuzhiyun * Reiner Sailer <sailer@watson.ibm.com>
10*4882a593Smuzhiyun * Kylene Hall <kjhall@us.ibm.com>
11*4882a593Smuzhiyun * Nayna Jain <nayna@linux.vnet.ibm.com>
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * Maintained by: <tpmdd-devel@lists.sourceforge.net>
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * Access to the event log created by a system's firmware / BIOS
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/seq_file.h>
19*4882a593Smuzhiyun #include <linux/efi.h>
20*4882a593Smuzhiyun #include <linux/fs.h>
21*4882a593Smuzhiyun #include <linux/security.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <linux/tpm_eventlog.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include "../tpm.h"
27*4882a593Smuzhiyun #include "common.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static const char* tcpa_event_type_strings[] = {
31*4882a593Smuzhiyun "PREBOOT",
32*4882a593Smuzhiyun "POST CODE",
33*4882a593Smuzhiyun "",
34*4882a593Smuzhiyun "NO ACTION",
35*4882a593Smuzhiyun "SEPARATOR",
36*4882a593Smuzhiyun "ACTION",
37*4882a593Smuzhiyun "EVENT TAG",
38*4882a593Smuzhiyun "S-CRTM Contents",
39*4882a593Smuzhiyun "S-CRTM Version",
40*4882a593Smuzhiyun "CPU Microcode",
41*4882a593Smuzhiyun "Platform Config Flags",
42*4882a593Smuzhiyun "Table of Devices",
43*4882a593Smuzhiyun "Compact Hash",
44*4882a593Smuzhiyun "IPL",
45*4882a593Smuzhiyun "IPL Partition Data",
46*4882a593Smuzhiyun "Non-Host Code",
47*4882a593Smuzhiyun "Non-Host Config",
48*4882a593Smuzhiyun "Non-Host Info"
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun static const char* tcpa_pc_event_id_strings[] = {
52*4882a593Smuzhiyun "",
53*4882a593Smuzhiyun "SMBIOS",
54*4882a593Smuzhiyun "BIS Certificate",
55*4882a593Smuzhiyun "POST BIOS ",
56*4882a593Smuzhiyun "ESCD ",
57*4882a593Smuzhiyun "CMOS",
58*4882a593Smuzhiyun "NVRAM",
59*4882a593Smuzhiyun "Option ROM",
60*4882a593Smuzhiyun "Option ROM config",
61*4882a593Smuzhiyun "",
62*4882a593Smuzhiyun "Option ROM microcode ",
63*4882a593Smuzhiyun "S-CRTM Version",
64*4882a593Smuzhiyun "S-CRTM Contents ",
65*4882a593Smuzhiyun "POST Contents ",
66*4882a593Smuzhiyun "Table of Devices",
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* returns pointer to start of pos. entry of tcg log */
tpm1_bios_measurements_start(struct seq_file * m,loff_t * pos)70*4882a593Smuzhiyun static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun loff_t i = 0;
73*4882a593Smuzhiyun struct tpm_chip *chip = m->private;
74*4882a593Smuzhiyun struct tpm_bios_log *log = &chip->log;
75*4882a593Smuzhiyun void *addr = log->bios_event_log;
76*4882a593Smuzhiyun void *limit = log->bios_event_log_end;
77*4882a593Smuzhiyun struct tcpa_event *event;
78*4882a593Smuzhiyun u32 converted_event_size;
79*4882a593Smuzhiyun u32 converted_event_type;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun /* read over *pos measurements */
82*4882a593Smuzhiyun do {
83*4882a593Smuzhiyun event = addr;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* check if current entry is valid */
86*4882a593Smuzhiyun if (addr + sizeof(struct tcpa_event) > limit)
87*4882a593Smuzhiyun return NULL;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun converted_event_size =
90*4882a593Smuzhiyun do_endian_conversion(event->event_size);
91*4882a593Smuzhiyun converted_event_type =
92*4882a593Smuzhiyun do_endian_conversion(event->event_type);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (((converted_event_type == 0) && (converted_event_size == 0))
95*4882a593Smuzhiyun || ((addr + sizeof(struct tcpa_event) + converted_event_size)
96*4882a593Smuzhiyun > limit))
97*4882a593Smuzhiyun return NULL;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (i++ == *pos)
100*4882a593Smuzhiyun break;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun addr += (sizeof(struct tcpa_event) + converted_event_size);
103*4882a593Smuzhiyun } while (1);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun return addr;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
tpm1_bios_measurements_next(struct seq_file * m,void * v,loff_t * pos)108*4882a593Smuzhiyun static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
109*4882a593Smuzhiyun loff_t *pos)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun struct tcpa_event *event = v;
112*4882a593Smuzhiyun struct tpm_chip *chip = m->private;
113*4882a593Smuzhiyun struct tpm_bios_log *log = &chip->log;
114*4882a593Smuzhiyun void *limit = log->bios_event_log_end;
115*4882a593Smuzhiyun u32 converted_event_size;
116*4882a593Smuzhiyun u32 converted_event_type;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun (*pos)++;
119*4882a593Smuzhiyun converted_event_size = do_endian_conversion(event->event_size);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun v += sizeof(struct tcpa_event) + converted_event_size;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /* now check if current entry is valid */
124*4882a593Smuzhiyun if ((v + sizeof(struct tcpa_event)) > limit)
125*4882a593Smuzhiyun return NULL;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun event = v;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun converted_event_size = do_endian_conversion(event->event_size);
130*4882a593Smuzhiyun converted_event_type = do_endian_conversion(event->event_type);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (((converted_event_type == 0) && (converted_event_size == 0)) ||
133*4882a593Smuzhiyun ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
134*4882a593Smuzhiyun return NULL;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun return v;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
tpm1_bios_measurements_stop(struct seq_file * m,void * v)139*4882a593Smuzhiyun static void tpm1_bios_measurements_stop(struct seq_file *m, void *v)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
get_event_name(char * dest,struct tcpa_event * event,unsigned char * event_entry)143*4882a593Smuzhiyun static int get_event_name(char *dest, struct tcpa_event *event,
144*4882a593Smuzhiyun unsigned char * event_entry)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun const char *name = "";
147*4882a593Smuzhiyun /* 41 so there is room for 40 data and 1 nul */
148*4882a593Smuzhiyun char data[41] = "";
149*4882a593Smuzhiyun int i, n_len = 0, d_len = 0;
150*4882a593Smuzhiyun struct tcpa_pc_event *pc_event;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun switch (do_endian_conversion(event->event_type)) {
153*4882a593Smuzhiyun case PREBOOT:
154*4882a593Smuzhiyun case POST_CODE:
155*4882a593Smuzhiyun case UNUSED:
156*4882a593Smuzhiyun case NO_ACTION:
157*4882a593Smuzhiyun case SCRTM_CONTENTS:
158*4882a593Smuzhiyun case SCRTM_VERSION:
159*4882a593Smuzhiyun case CPU_MICROCODE:
160*4882a593Smuzhiyun case PLATFORM_CONFIG_FLAGS:
161*4882a593Smuzhiyun case TABLE_OF_DEVICES:
162*4882a593Smuzhiyun case COMPACT_HASH:
163*4882a593Smuzhiyun case IPL:
164*4882a593Smuzhiyun case IPL_PARTITION_DATA:
165*4882a593Smuzhiyun case NONHOST_CODE:
166*4882a593Smuzhiyun case NONHOST_CONFIG:
167*4882a593Smuzhiyun case NONHOST_INFO:
168*4882a593Smuzhiyun name = tcpa_event_type_strings[do_endian_conversion
169*4882a593Smuzhiyun (event->event_type)];
170*4882a593Smuzhiyun n_len = strlen(name);
171*4882a593Smuzhiyun break;
172*4882a593Smuzhiyun case SEPARATOR:
173*4882a593Smuzhiyun case ACTION:
174*4882a593Smuzhiyun if (MAX_TEXT_EVENT >
175*4882a593Smuzhiyun do_endian_conversion(event->event_size)) {
176*4882a593Smuzhiyun name = event_entry;
177*4882a593Smuzhiyun n_len = do_endian_conversion(event->event_size);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun break;
180*4882a593Smuzhiyun case EVENT_TAG:
181*4882a593Smuzhiyun pc_event = (struct tcpa_pc_event *)event_entry;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* ToDo Row data -> Base64 */
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun switch (do_endian_conversion(pc_event->event_id)) {
186*4882a593Smuzhiyun case SMBIOS:
187*4882a593Smuzhiyun case BIS_CERT:
188*4882a593Smuzhiyun case CMOS:
189*4882a593Smuzhiyun case NVRAM:
190*4882a593Smuzhiyun case OPTION_ROM_EXEC:
191*4882a593Smuzhiyun case OPTION_ROM_CONFIG:
192*4882a593Smuzhiyun case S_CRTM_VERSION:
193*4882a593Smuzhiyun name = tcpa_pc_event_id_strings[do_endian_conversion
194*4882a593Smuzhiyun (pc_event->event_id)];
195*4882a593Smuzhiyun n_len = strlen(name);
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun /* hash data */
198*4882a593Smuzhiyun case POST_BIOS_ROM:
199*4882a593Smuzhiyun case ESCD:
200*4882a593Smuzhiyun case OPTION_ROM_MICROCODE:
201*4882a593Smuzhiyun case S_CRTM_CONTENTS:
202*4882a593Smuzhiyun case POST_CONTENTS:
203*4882a593Smuzhiyun name = tcpa_pc_event_id_strings[do_endian_conversion
204*4882a593Smuzhiyun (pc_event->event_id)];
205*4882a593Smuzhiyun n_len = strlen(name);
206*4882a593Smuzhiyun for (i = 0; i < 20; i++)
207*4882a593Smuzhiyun d_len += sprintf(&data[2*i], "%02x",
208*4882a593Smuzhiyun pc_event->event_data[i]);
209*4882a593Smuzhiyun break;
210*4882a593Smuzhiyun default:
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun default:
214*4882a593Smuzhiyun break;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
218*4882a593Smuzhiyun n_len, name, d_len, data);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
tpm1_binary_bios_measurements_show(struct seq_file * m,void * v)222*4882a593Smuzhiyun static int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun struct tcpa_event *event = v;
225*4882a593Smuzhiyun struct tcpa_event temp_event;
226*4882a593Smuzhiyun char *temp_ptr;
227*4882a593Smuzhiyun int i;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun memcpy(&temp_event, event, sizeof(struct tcpa_event));
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* convert raw integers for endianness */
232*4882a593Smuzhiyun temp_event.pcr_index = do_endian_conversion(event->pcr_index);
233*4882a593Smuzhiyun temp_event.event_type = do_endian_conversion(event->event_type);
234*4882a593Smuzhiyun temp_event.event_size = do_endian_conversion(event->event_size);
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun temp_ptr = (char *) &temp_event;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
239*4882a593Smuzhiyun seq_putc(m, temp_ptr[i]);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun temp_ptr = (char *) v;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun for (i = (sizeof(struct tcpa_event) - 1);
244*4882a593Smuzhiyun i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
245*4882a593Smuzhiyun seq_putc(m, temp_ptr[i]);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun return 0;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
tpm1_ascii_bios_measurements_show(struct seq_file * m,void * v)251*4882a593Smuzhiyun static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun int len = 0;
254*4882a593Smuzhiyun char *eventname;
255*4882a593Smuzhiyun struct tcpa_event *event = v;
256*4882a593Smuzhiyun unsigned char *event_entry =
257*4882a593Smuzhiyun (unsigned char *)(v + sizeof(struct tcpa_event));
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
260*4882a593Smuzhiyun if (!eventname) {
261*4882a593Smuzhiyun printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
262*4882a593Smuzhiyun __func__);
263*4882a593Smuzhiyun return -EFAULT;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* 1st: PCR */
267*4882a593Smuzhiyun seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* 2nd: SHA1 */
270*4882a593Smuzhiyun seq_printf(m, "%20phN", event->pcr_value);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* 3rd: event type identifier */
273*4882a593Smuzhiyun seq_printf(m, " %02x", do_endian_conversion(event->event_type));
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun len += get_event_name(eventname, event, event_entry);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* 4th: eventname <= max + \'0' delimiter */
278*4882a593Smuzhiyun seq_printf(m, " %s\n", eventname);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun kfree(eventname);
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun const struct seq_operations tpm1_ascii_b_measurements_seqops = {
285*4882a593Smuzhiyun .start = tpm1_bios_measurements_start,
286*4882a593Smuzhiyun .next = tpm1_bios_measurements_next,
287*4882a593Smuzhiyun .stop = tpm1_bios_measurements_stop,
288*4882a593Smuzhiyun .show = tpm1_ascii_bios_measurements_show,
289*4882a593Smuzhiyun };
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun const struct seq_operations tpm1_binary_b_measurements_seqops = {
292*4882a593Smuzhiyun .start = tpm1_bios_measurements_start,
293*4882a593Smuzhiyun .next = tpm1_bios_measurements_next,
294*4882a593Smuzhiyun .stop = tpm1_bios_measurements_stop,
295*4882a593Smuzhiyun .show = tpm1_binary_bios_measurements_show,
296*4882a593Smuzhiyun };
297