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