1/*
2 * Copyright (C) 2005 IBM Corporation
3 *
4 * Authors:
5 *	Seiji Munetoh <munetoh@jp.ibm.com>
6 *	Stefan Berger <stefanb@us.ibm.com>
7 *	Reiner Sailer <sailer@watson.ibm.com>
8 *	Kylene Hall <kjhall@us.ibm.com>
9 *
10 * Access to the eventlog extended by the TCG BIOS of PC platform
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 *
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 <acpi/acpi.h>
24#include <acpi/actypes.h>
25#include <acpi/actbl.h>
26#include "tpm.h"
27
28#define TCG_EVENT_NAME_LEN_MAX	255
29#define MAX_TEXT_EVENT		1000	/* Max event string length */
30#define ACPI_TCPA_SIG		"TCPA"	/* 0x41504354 /'TCPA' */
31
32enum bios_platform_class {
33	BIOS_CLIENT = 0x00,
34	BIOS_SERVER = 0x01,
35};
36
37struct tpm_bios_log {
38	void *bios_event_log;
39	void *bios_event_log_end;
40};
41
42struct acpi_tcpa {
43	struct acpi_table_header hdr;
44	u16 platform_class;
45	union {
46		struct client_hdr {
47			u32 log_max_len __attribute__ ((packed));
48			u64 log_start_addr __attribute__ ((packed));
49		} client;
50		struct server_hdr {
51			u16 reserved;
52			u64 log_max_len __attribute__ ((packed));
53			u64 log_start_addr __attribute__ ((packed));
54		} server;
55	};
56};
57
58struct tcpa_event {
59	u32 pcr_index;
60	u32 event_type;
61	u8 pcr_value[20];	/* SHA1 */
62	u32 event_size;
63	u8 event_data[0];
64};
65
66enum tcpa_event_types {
67	PREBOOT = 0,
68	POST_CODE,
69	UNUSED,
70	NO_ACTION,
71	SEPARATOR,
72	ACTION,
73	EVENT_TAG,
74	SCRTM_CONTENTS,
75	SCRTM_VERSION,
76	CPU_MICROCODE,
77	PLATFORM_CONFIG_FLAGS,
78	TABLE_OF_DEVICES,
79	COMPACT_HASH,
80	IPL,
81	IPL_PARTITION_DATA,
82	NONHOST_CODE,
83	NONHOST_CONFIG,
84	NONHOST_INFO,
85};
86
87static const char* tcpa_event_type_strings[] = {
88	"PREBOOT",
89	"POST CODE",
90	"",
91	"NO ACTION",
92	"SEPARATOR",
93	"ACTION",
94	"EVENT TAG",
95	"S-CRTM Contents",
96	"S-CRTM Version",
97	"CPU Microcode",
98	"Platform Config Flags",
99	"Table of Devices",
100	"Compact Hash",
101	"IPL",
102	"IPL Partition Data",
103	"Non-Host Code",
104	"Non-Host Config",
105	"Non-Host Info"
106};
107
108struct tcpa_pc_event {
109	u32 event_id;
110	u32 event_size;
111	u8 event_data[0];
112};
113
114enum tcpa_pc_event_ids {
115	SMBIOS = 1,
116	BIS_CERT,
117	POST_BIOS_ROM,
118	ESCD,
119	CMOS,
120	NVRAM,
121	OPTION_ROM_EXEC,
122	OPTION_ROM_CONFIG,
123	OPTION_ROM_MICROCODE = 10,
124	S_CRTM_VERSION,
125	S_CRTM_CONTENTS,
126	POST_CONTENTS,
127	HOST_TABLE_OF_DEVICES,
128};
129
130static const char* tcpa_pc_event_id_strings[] = {
131	"",
132	"SMBIOS",
133	"BIS Certificate",
134	"POST BIOS ",
135	"ESCD ",
136	"CMOS",
137	"NVRAM",
138	"Option ROM",
139	"Option ROM config",
140	"",
141	"Option ROM microcode ",
142	"S-CRTM Version",
143	"S-CRTM Contents ",
144	"POST Contents ",
145	"Table of Devices",
146};
147
148/* returns pointer to start of pos. entry of tcg log */
149static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
150{
151	loff_t i;
152	struct tpm_bios_log *log = m->private;
153	void *addr = log->bios_event_log;
154	void *limit = log->bios_event_log_end;
155	struct tcpa_event *event;
156
157	/* read over *pos measurements */
158	for (i = 0; i < *pos; i++) {
159		event = addr;
160
161		if ((addr + sizeof(struct tcpa_event)) < limit) {
162			if (event->event_type == 0 && event->event_size == 0)
163				return NULL;
164			addr += sizeof(struct tcpa_event) + event->event_size;
165		}
166	}
167
168	/* now check if current entry is valid */
169	if ((addr + sizeof(struct tcpa_event)) >= limit)
170		return NULL;
171
172	event = addr;
173
174	if ((event->event_type == 0 && event->event_size == 0) ||
175	    ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
176		return NULL;
177
178	return addr;
179}
180
181static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
182					loff_t *pos)
183{
184	struct tcpa_event *event = v;
185	struct tpm_bios_log *log = m->private;
186	void *limit = log->bios_event_log_end;
187
188	v += sizeof(struct tcpa_event) + event->event_size;
189
190	/* now check if current entry is valid */
191	if ((v + sizeof(struct tcpa_event)) >= limit)
192		return NULL;
193
194	event = v;
195
196	if (event->event_type == 0 && event->event_size == 0)
197		return NULL;
198
199	if ((event->event_type == 0 && event->event_size == 0) ||
200	    ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
201		return NULL;
202
203	(*pos)++;
204	return v;
205}
206
207static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
208{
209}
210
211static int get_event_name(char *dest, struct tcpa_event *event,
212			unsigned char * event_entry)
213{
214	const char *name = "";
215	char data[40] = "";
216	int i, n_len = 0, d_len = 0;
217	struct tcpa_pc_event *pc_event;
218
219	switch(event->event_type) {
220	case PREBOOT:
221	case POST_CODE:
222	case UNUSED:
223	case NO_ACTION:
224	case SCRTM_CONTENTS:
225	case SCRTM_VERSION:
226	case CPU_MICROCODE:
227	case PLATFORM_CONFIG_FLAGS:
228	case TABLE_OF_DEVICES:
229	case COMPACT_HASH:
230	case IPL:
231	case IPL_PARTITION_DATA:
232	case NONHOST_CODE:
233	case NONHOST_CONFIG:
234	case NONHOST_INFO:
235		name = tcpa_event_type_strings[event->event_type];
236		n_len = strlen(name);
237		break;
238	case SEPARATOR:
239	case ACTION:
240		if (MAX_TEXT_EVENT > event->event_size) {
241			name = event_entry;
242			n_len = event->event_size;
243		}
244		break;
245	case EVENT_TAG:
246		pc_event = (struct tcpa_pc_event *)event_entry;
247
248		/* ToDo Row data -> Base64 */
249
250		switch (pc_event->event_id) {
251		case SMBIOS:
252		case BIS_CERT:
253		case CMOS:
254		case NVRAM:
255		case OPTION_ROM_EXEC:
256		case OPTION_ROM_CONFIG:
257		case S_CRTM_VERSION:
258			name = tcpa_pc_event_id_strings[pc_event->event_id];
259			n_len = strlen(name);
260			break;
261		/* hash data */
262		case POST_BIOS_ROM:
263		case ESCD:
264		case OPTION_ROM_MICROCODE:
265		case S_CRTM_CONTENTS:
266		case POST_CONTENTS:
267			name = tcpa_pc_event_id_strings[pc_event->event_id];
268			n_len = strlen(name);
269			for (i = 0; i < 20; i++)
270				d_len += sprintf(&data[2*i], "%02x",
271						pc_event->event_data[i]);
272			break;
273		default:
274			break;
275		}
276	default:
277		break;
278	}
279
280	return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
281			n_len, name, d_len, data);
282
283}
284
285static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
286{
287	struct tcpa_event *event = v;
288	char *data = v;
289	int i;
290
291	for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
292		seq_putc(m, data[i]);
293
294	return 0;
295}
296
297static int tpm_bios_measurements_release(struct inode *inode,
298					 struct file *file)
299{
300	struct seq_file *seq = file->private_data;
301	struct tpm_bios_log *log = seq->private;
302
303	if (log) {
304		kfree(log->bios_event_log);
305		kfree(log);
306	}
307
308	return seq_release(inode, file);
309}
310
311static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
312{
313	int len = 0;
314	int i;
315	char *eventname;
316	struct tcpa_event *event = v;
317	unsigned char *event_entry =
318	    (unsigned char *) (v + sizeof(struct tcpa_event));
319
320	eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
321	if (!eventname) {
322		printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
323		       __func__);
324		return -EFAULT;
325	}
326
327	seq_printf(m, "%2d ", event->pcr_index);
328
329	/* 2nd: SHA1 */
330	for (i = 0; i < 20; i++)
331		seq_printf(m, "%02x", event->pcr_value[i]);
332
333	/* 3rd: event type identifier */
334	seq_printf(m, " %02x", event->event_type);
335
336	len += get_event_name(eventname, event, event_entry);
337
338	/* 4th: eventname <= max + \'0' delimiter */
339	seq_printf(m, " %s\n", eventname);
340
341	kfree(eventname);
342	return 0;
343}
344
345static struct seq_operations tpm_ascii_b_measurments_seqops = {
346	.start = tpm_bios_measurements_start,
347	.next = tpm_bios_measurements_next,
348	.stop = tpm_bios_measurements_stop,
349	.show = tpm_ascii_bios_measurements_show,
350};
351
352static struct seq_operations tpm_binary_b_measurments_seqops = {
353	.start = tpm_bios_measurements_start,
354	.next = tpm_bios_measurements_next,
355	.stop = tpm_bios_measurements_stop,
356	.show = tpm_binary_bios_measurements_show,
357};
358
359/* read binary bios log */
360static int read_log(struct tpm_bios_log *log)
361{
362	struct acpi_tcpa *buff;
363	acpi_status status;
364	struct acpi_table_header *virt;
365	u64 len, start;
366
367	if (log->bios_event_log != NULL) {
368		printk(KERN_ERR
369		       "%s: ERROR - Eventlog already initialized\n",
370		       __func__);
371		return -EFAULT;
372	}
373
374	/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
375	status = acpi_get_table(ACPI_SIG_TCPA, 1,
376				(struct acpi_table_header **)&buff);
377
378	if (ACPI_FAILURE(status)) {
379		printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
380		       __func__);
381		return -EIO;
382	}
383
384	switch(buff->platform_class) {
385	case BIOS_SERVER:
386		len = buff->server.log_max_len;
387		start = buff->server.log_start_addr;
388		break;
389	case BIOS_CLIENT:
390	default:
391		len = buff->client.log_max_len;
392		start = buff->client.log_start_addr;
393		break;
394	}
395	if (!len) {
396		printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
397		return -EIO;
398	}
399
400	/* malloc EventLog space */
401	log->bios_event_log = kmalloc(len, GFP_KERNEL);
402	if (!log->bios_event_log) {
403		printk("%s: ERROR - Not enough  Memory for BIOS measurements\n",
404			__func__);
405		return -ENOMEM;
406	}
407
408	log->bios_event_log_end = log->bios_event_log + len;
409
410	virt = acpi_os_map_memory(start, len);
411
412	memcpy(log->bios_event_log, virt, len);
413
414	acpi_os_unmap_memory(virt, len);
415	return 0;
416}
417
418static int tpm_ascii_bios_measurements_open(struct inode *inode,
419					    struct file *file)
420{
421	int err;
422	struct tpm_bios_log *log;
423	struct seq_file *seq;
424
425	log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
426	if (!log)
427		return -ENOMEM;
428
429	if ((err = read_log(log)))
430		return err;
431
432	/* now register seq file */
433	err = seq_open(file, &tpm_ascii_b_measurments_seqops);
434	if (!err) {
435		seq = file->private_data;
436		seq->private = log;
437	} else {
438		kfree(log->bios_event_log);
439		kfree(log);
440	}
441	return err;
442}
443
444const struct file_operations tpm_ascii_bios_measurements_ops = {
445	.open = tpm_ascii_bios_measurements_open,
446	.read = seq_read,
447	.llseek = seq_lseek,
448	.release = tpm_bios_measurements_release,
449};
450
451static int tpm_binary_bios_measurements_open(struct inode *inode,
452					     struct file *file)
453{
454	int err;
455	struct tpm_bios_log *log;
456	struct seq_file *seq;
457
458	log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
459	if (!log)
460		return -ENOMEM;
461
462	if ((err = read_log(log)))
463		return err;
464
465	/* now register seq file */
466	err = seq_open(file, &tpm_binary_b_measurments_seqops);
467	if (!err) {
468		seq = file->private_data;
469		seq->private = log;
470	} else {
471		kfree(log->bios_event_log);
472		kfree(log);
473	}
474	return err;
475}
476
477const struct file_operations tpm_binary_bios_measurements_ops = {
478	.open = tpm_binary_bios_measurements_open,
479	.read = seq_read,
480	.llseek = seq_lseek,
481	.release = tpm_bios_measurements_release,
482};
483
484static int is_bad(void *p)
485{
486	if (!p)
487		return 1;
488	if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
489		return 1;
490	return 0;
491}
492
493struct dentry **tpm_bios_log_setup(char *name)
494{
495	struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
496
497	tpm_dir = securityfs_create_dir(name, NULL);
498	if (is_bad(tpm_dir))
499		goto out;
500
501	bin_file =
502	    securityfs_create_file("binary_bios_measurements",
503				   S_IRUSR | S_IRGRP, tpm_dir, NULL,
504				   &tpm_binary_bios_measurements_ops);
505	if (is_bad(bin_file))
506		goto out_tpm;
507
508	ascii_file =
509	    securityfs_create_file("ascii_bios_measurements",
510				   S_IRUSR | S_IRGRP, tpm_dir, NULL,
511				   &tpm_ascii_bios_measurements_ops);
512	if (is_bad(ascii_file))
513		goto out_bin;
514
515	ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
516	if (!ret)
517		goto out_ascii;
518
519	ret[0] = ascii_file;
520	ret[1] = bin_file;
521	ret[2] = tpm_dir;
522
523	return ret;
524
525out_ascii:
526	securityfs_remove(ascii_file);
527out_bin:
528	securityfs_remove(bin_file);
529out_tpm:
530	securityfs_remove(tpm_dir);
531out:
532	return NULL;
533}
534EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
535
536void tpm_bios_log_teardown(struct dentry **lst)
537{
538	int i;
539
540	for (i = 0; i < 3; i++)
541		securityfs_remove(lst[i]);
542}
543EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
544MODULE_LICENSE("GPL");
545