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