xref: /linux/drivers/char/tpm/eventlog/tpm1.c (revision df333d058a60a8dc282009a483124983669b4203)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20bfb2374SThiebaud Weksteen /*
30bfb2374SThiebaud Weksteen  * Copyright (C) 2005, 2012 IBM Corporation
40bfb2374SThiebaud Weksteen  *
50bfb2374SThiebaud Weksteen  * Authors:
60bfb2374SThiebaud Weksteen  *	Kent Yoder <key@linux.vnet.ibm.com>
70bfb2374SThiebaud Weksteen  *	Seiji Munetoh <munetoh@jp.ibm.com>
80bfb2374SThiebaud Weksteen  *	Stefan Berger <stefanb@us.ibm.com>
90bfb2374SThiebaud Weksteen  *	Reiner Sailer <sailer@watson.ibm.com>
100bfb2374SThiebaud Weksteen  *	Kylene Hall <kjhall@us.ibm.com>
110bfb2374SThiebaud Weksteen  *	Nayna Jain <nayna@linux.vnet.ibm.com>
120bfb2374SThiebaud Weksteen  *
130bfb2374SThiebaud Weksteen  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
140bfb2374SThiebaud Weksteen  *
150bfb2374SThiebaud Weksteen  * Access to the event log created by a system's firmware / BIOS
160bfb2374SThiebaud Weksteen  */
170bfb2374SThiebaud Weksteen 
180bfb2374SThiebaud Weksteen #include <linux/seq_file.h>
190bfb2374SThiebaud Weksteen #include <linux/efi.h>
200bfb2374SThiebaud Weksteen #include <linux/fs.h>
210bfb2374SThiebaud Weksteen #include <linux/security.h>
220bfb2374SThiebaud Weksteen #include <linux/module.h>
230bfb2374SThiebaud Weksteen #include <linux/slab.h>
240bfb2374SThiebaud Weksteen #include <linux/tpm_eventlog.h>
250bfb2374SThiebaud Weksteen 
260bfb2374SThiebaud Weksteen #include "../tpm.h"
2775d647f5SThiebaud Weksteen #include "common.h"
280bfb2374SThiebaud Weksteen 
290bfb2374SThiebaud Weksteen 
300bfb2374SThiebaud Weksteen static const char* tcpa_event_type_strings[] = {
310bfb2374SThiebaud Weksteen 	"PREBOOT",
320bfb2374SThiebaud Weksteen 	"POST CODE",
330bfb2374SThiebaud Weksteen 	"",
340bfb2374SThiebaud Weksteen 	"NO ACTION",
350bfb2374SThiebaud Weksteen 	"SEPARATOR",
360bfb2374SThiebaud Weksteen 	"ACTION",
370bfb2374SThiebaud Weksteen 	"EVENT TAG",
380bfb2374SThiebaud Weksteen 	"S-CRTM Contents",
390bfb2374SThiebaud Weksteen 	"S-CRTM Version",
400bfb2374SThiebaud Weksteen 	"CPU Microcode",
410bfb2374SThiebaud Weksteen 	"Platform Config Flags",
420bfb2374SThiebaud Weksteen 	"Table of Devices",
430bfb2374SThiebaud Weksteen 	"Compact Hash",
440bfb2374SThiebaud Weksteen 	"IPL",
450bfb2374SThiebaud Weksteen 	"IPL Partition Data",
460bfb2374SThiebaud Weksteen 	"Non-Host Code",
470bfb2374SThiebaud Weksteen 	"Non-Host Config",
480bfb2374SThiebaud Weksteen 	"Non-Host Info"
490bfb2374SThiebaud Weksteen };
500bfb2374SThiebaud Weksteen 
510bfb2374SThiebaud Weksteen static const char* tcpa_pc_event_id_strings[] = {
520bfb2374SThiebaud Weksteen 	"",
530bfb2374SThiebaud Weksteen 	"SMBIOS",
540bfb2374SThiebaud Weksteen 	"BIS Certificate",
550bfb2374SThiebaud Weksteen 	"POST BIOS ",
560bfb2374SThiebaud Weksteen 	"ESCD ",
570bfb2374SThiebaud Weksteen 	"CMOS",
580bfb2374SThiebaud Weksteen 	"NVRAM",
590bfb2374SThiebaud Weksteen 	"Option ROM",
600bfb2374SThiebaud Weksteen 	"Option ROM config",
610bfb2374SThiebaud Weksteen 	"",
620bfb2374SThiebaud Weksteen 	"Option ROM microcode ",
630bfb2374SThiebaud Weksteen 	"S-CRTM Version",
640bfb2374SThiebaud Weksteen 	"S-CRTM Contents ",
650bfb2374SThiebaud Weksteen 	"POST Contents ",
660bfb2374SThiebaud Weksteen 	"Table of Devices",
670bfb2374SThiebaud Weksteen };
680bfb2374SThiebaud Weksteen 
690bfb2374SThiebaud Weksteen /* returns pointer to start of pos. entry of tcg log */
709b01b535SThiebaud Weksteen static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
710bfb2374SThiebaud Weksteen {
72bb3b6b0fSJia Zhang 	loff_t i = 0;
730bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
740bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
750bfb2374SThiebaud Weksteen 	void *addr = log->bios_event_log;
760bfb2374SThiebaud Weksteen 	void *limit = log->bios_event_log_end;
770bfb2374SThiebaud Weksteen 	struct tcpa_event *event;
780bfb2374SThiebaud Weksteen 	u32 converted_event_size;
790bfb2374SThiebaud Weksteen 	u32 converted_event_type;
800bfb2374SThiebaud Weksteen 
810bfb2374SThiebaud Weksteen 	/* read over *pos measurements */
82bb3b6b0fSJia Zhang 	do {
830bfb2374SThiebaud Weksteen 		event = addr;
840bfb2374SThiebaud Weksteen 
85bb3b6b0fSJia Zhang 		/* check if current entry is valid */
8664494d39SJia Zhang 		if (addr + sizeof(struct tcpa_event) > limit)
87bb3b6b0fSJia Zhang 			return NULL;
88bb3b6b0fSJia Zhang 
890bfb2374SThiebaud Weksteen 		converted_event_size =
900bfb2374SThiebaud Weksteen 		    do_endian_conversion(event->event_size);
910bfb2374SThiebaud Weksteen 		converted_event_type =
920bfb2374SThiebaud Weksteen 		    do_endian_conversion(event->event_type);
930bfb2374SThiebaud Weksteen 
940bfb2374SThiebaud Weksteen 		if (((converted_event_type == 0) && (converted_event_size == 0))
950bfb2374SThiebaud Weksteen 		    || ((addr + sizeof(struct tcpa_event) + converted_event_size)
9664494d39SJia Zhang 			> limit))
970bfb2374SThiebaud Weksteen 			return NULL;
980bfb2374SThiebaud Weksteen 
99bb3b6b0fSJia Zhang 		if (i++ == *pos)
100bb3b6b0fSJia Zhang 			break;
101bb3b6b0fSJia Zhang 
102bb3b6b0fSJia Zhang 		addr += (sizeof(struct tcpa_event) + converted_event_size);
103bb3b6b0fSJia Zhang 	} while (1);
104bb3b6b0fSJia Zhang 
1050bfb2374SThiebaud Weksteen 	return addr;
1060bfb2374SThiebaud Weksteen }
1070bfb2374SThiebaud Weksteen 
1089b01b535SThiebaud Weksteen static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
1090bfb2374SThiebaud Weksteen 					loff_t *pos)
1100bfb2374SThiebaud Weksteen {
1110bfb2374SThiebaud Weksteen 	struct tcpa_event *event = v;
1120bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
1130bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
1140bfb2374SThiebaud Weksteen 	void *limit = log->bios_event_log_end;
1150bfb2374SThiebaud Weksteen 	u32 converted_event_size;
1160bfb2374SThiebaud Weksteen 	u32 converted_event_type;
1170bfb2374SThiebaud Weksteen 
118d7a47b96SVasily Averin 	(*pos)++;
1190bfb2374SThiebaud Weksteen 	converted_event_size = do_endian_conversion(event->event_size);
1200bfb2374SThiebaud Weksteen 
1210bfb2374SThiebaud Weksteen 	v += sizeof(struct tcpa_event) + converted_event_size;
1220bfb2374SThiebaud Weksteen 
1230bfb2374SThiebaud Weksteen 	/* now check if current entry is valid */
12464494d39SJia Zhang 	if ((v + sizeof(struct tcpa_event)) > limit)
1250bfb2374SThiebaud Weksteen 		return NULL;
1260bfb2374SThiebaud Weksteen 
1270bfb2374SThiebaud Weksteen 	event = v;
1280bfb2374SThiebaud Weksteen 
1290bfb2374SThiebaud Weksteen 	converted_event_size = do_endian_conversion(event->event_size);
1300bfb2374SThiebaud Weksteen 	converted_event_type = do_endian_conversion(event->event_type);
1310bfb2374SThiebaud Weksteen 
1320bfb2374SThiebaud Weksteen 	if (((converted_event_type == 0) && (converted_event_size == 0)) ||
13364494d39SJia Zhang 	    ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
1340bfb2374SThiebaud Weksteen 		return NULL;
1350bfb2374SThiebaud Weksteen 
1360bfb2374SThiebaud Weksteen 	return v;
1370bfb2374SThiebaud Weksteen }
1380bfb2374SThiebaud Weksteen 
1399b01b535SThiebaud Weksteen static void tpm1_bios_measurements_stop(struct seq_file *m, void *v)
1400bfb2374SThiebaud Weksteen {
1410bfb2374SThiebaud Weksteen }
1420bfb2374SThiebaud Weksteen 
1430bfb2374SThiebaud Weksteen static int get_event_name(char *dest, struct tcpa_event *event,
1440bfb2374SThiebaud Weksteen 			unsigned char * event_entry)
1450bfb2374SThiebaud Weksteen {
1460bfb2374SThiebaud Weksteen 	const char *name = "";
1470bfb2374SThiebaud Weksteen 	/* 41 so there is room for 40 data and 1 nul */
1480bfb2374SThiebaud Weksteen 	char data[41] = "";
1490bfb2374SThiebaud Weksteen 	int i, n_len = 0, d_len = 0;
1500bfb2374SThiebaud Weksteen 	struct tcpa_pc_event *pc_event;
1510bfb2374SThiebaud Weksteen 
1520bfb2374SThiebaud Weksteen 	switch (do_endian_conversion(event->event_type)) {
1530bfb2374SThiebaud Weksteen 	case PREBOOT:
1540bfb2374SThiebaud Weksteen 	case POST_CODE:
1550bfb2374SThiebaud Weksteen 	case UNUSED:
1560bfb2374SThiebaud Weksteen 	case NO_ACTION:
1570bfb2374SThiebaud Weksteen 	case SCRTM_CONTENTS:
1580bfb2374SThiebaud Weksteen 	case SCRTM_VERSION:
1590bfb2374SThiebaud Weksteen 	case CPU_MICROCODE:
1600bfb2374SThiebaud Weksteen 	case PLATFORM_CONFIG_FLAGS:
1610bfb2374SThiebaud Weksteen 	case TABLE_OF_DEVICES:
1620bfb2374SThiebaud Weksteen 	case COMPACT_HASH:
1630bfb2374SThiebaud Weksteen 	case IPL:
1640bfb2374SThiebaud Weksteen 	case IPL_PARTITION_DATA:
1650bfb2374SThiebaud Weksteen 	case NONHOST_CODE:
1660bfb2374SThiebaud Weksteen 	case NONHOST_CONFIG:
1670bfb2374SThiebaud Weksteen 	case NONHOST_INFO:
1680bfb2374SThiebaud Weksteen 		name = tcpa_event_type_strings[do_endian_conversion
1690bfb2374SThiebaud Weksteen 						(event->event_type)];
1700bfb2374SThiebaud Weksteen 		n_len = strlen(name);
1710bfb2374SThiebaud Weksteen 		break;
1720bfb2374SThiebaud Weksteen 	case SEPARATOR:
1730bfb2374SThiebaud Weksteen 	case ACTION:
1740bfb2374SThiebaud Weksteen 		if (MAX_TEXT_EVENT >
1750bfb2374SThiebaud Weksteen 		    do_endian_conversion(event->event_size)) {
1760bfb2374SThiebaud Weksteen 			name = event_entry;
1770bfb2374SThiebaud Weksteen 			n_len = do_endian_conversion(event->event_size);
1780bfb2374SThiebaud Weksteen 		}
1790bfb2374SThiebaud Weksteen 		break;
1800bfb2374SThiebaud Weksteen 	case EVENT_TAG:
1810bfb2374SThiebaud Weksteen 		pc_event = (struct tcpa_pc_event *)event_entry;
1820bfb2374SThiebaud Weksteen 
1830bfb2374SThiebaud Weksteen 		/* ToDo Row data -> Base64 */
1840bfb2374SThiebaud Weksteen 
1850bfb2374SThiebaud Weksteen 		switch (do_endian_conversion(pc_event->event_id)) {
1860bfb2374SThiebaud Weksteen 		case SMBIOS:
1870bfb2374SThiebaud Weksteen 		case BIS_CERT:
1880bfb2374SThiebaud Weksteen 		case CMOS:
1890bfb2374SThiebaud Weksteen 		case NVRAM:
1900bfb2374SThiebaud Weksteen 		case OPTION_ROM_EXEC:
1910bfb2374SThiebaud Weksteen 		case OPTION_ROM_CONFIG:
1920bfb2374SThiebaud Weksteen 		case S_CRTM_VERSION:
1930bfb2374SThiebaud Weksteen 			name = tcpa_pc_event_id_strings[do_endian_conversion
1940bfb2374SThiebaud Weksteen 							(pc_event->event_id)];
1950bfb2374SThiebaud Weksteen 			n_len = strlen(name);
1960bfb2374SThiebaud Weksteen 			break;
1970bfb2374SThiebaud Weksteen 		/* hash data */
1980bfb2374SThiebaud Weksteen 		case POST_BIOS_ROM:
1990bfb2374SThiebaud Weksteen 		case ESCD:
2000bfb2374SThiebaud Weksteen 		case OPTION_ROM_MICROCODE:
2010bfb2374SThiebaud Weksteen 		case S_CRTM_CONTENTS:
2020bfb2374SThiebaud Weksteen 		case POST_CONTENTS:
2030bfb2374SThiebaud Weksteen 			name = tcpa_pc_event_id_strings[do_endian_conversion
2040bfb2374SThiebaud Weksteen 							(pc_event->event_id)];
2050bfb2374SThiebaud Weksteen 			n_len = strlen(name);
2060bfb2374SThiebaud Weksteen 			for (i = 0; i < 20; i++)
2070bfb2374SThiebaud Weksteen 				d_len += sprintf(&data[2*i], "%02x",
2080bfb2374SThiebaud Weksteen 						pc_event->event_data[i]);
2090bfb2374SThiebaud Weksteen 			break;
2100bfb2374SThiebaud Weksteen 		default:
2110bfb2374SThiebaud Weksteen 			break;
2120bfb2374SThiebaud Weksteen 		}
213d87719c1SGustavo A. R. Silva 		break;
2140bfb2374SThiebaud Weksteen 	default:
2150bfb2374SThiebaud Weksteen 		break;
2160bfb2374SThiebaud Weksteen 	}
2170bfb2374SThiebaud Weksteen 
2180bfb2374SThiebaud Weksteen 	return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
2190bfb2374SThiebaud Weksteen 			n_len, name, d_len, data);
2200bfb2374SThiebaud Weksteen 
2210bfb2374SThiebaud Weksteen }
2220bfb2374SThiebaud Weksteen 
2239b01b535SThiebaud Weksteen static int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
2240bfb2374SThiebaud Weksteen {
2250bfb2374SThiebaud Weksteen 	struct tcpa_event *event = v;
2260bfb2374SThiebaud Weksteen 	struct tcpa_event temp_event;
2270bfb2374SThiebaud Weksteen 	char *temp_ptr;
2280bfb2374SThiebaud Weksteen 	int i;
2290bfb2374SThiebaud Weksteen 
2300bfb2374SThiebaud Weksteen 	memcpy(&temp_event, event, sizeof(struct tcpa_event));
2310bfb2374SThiebaud Weksteen 
2320bfb2374SThiebaud Weksteen 	/* convert raw integers for endianness */
2330bfb2374SThiebaud Weksteen 	temp_event.pcr_index = do_endian_conversion(event->pcr_index);
2340bfb2374SThiebaud Weksteen 	temp_event.event_type = do_endian_conversion(event->event_type);
2350bfb2374SThiebaud Weksteen 	temp_event.event_size = do_endian_conversion(event->event_size);
2360bfb2374SThiebaud Weksteen 
2370bfb2374SThiebaud Weksteen 	temp_ptr = (char *) &temp_event;
2380bfb2374SThiebaud Weksteen 
2390bfb2374SThiebaud Weksteen 	for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
2400bfb2374SThiebaud Weksteen 		seq_putc(m, temp_ptr[i]);
2410bfb2374SThiebaud Weksteen 
2420bfb2374SThiebaud Weksteen 	temp_ptr = (char *) v;
2430bfb2374SThiebaud Weksteen 
2440bfb2374SThiebaud Weksteen 	for (i = (sizeof(struct tcpa_event) - 1);
2450bfb2374SThiebaud Weksteen 	     i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
2460bfb2374SThiebaud Weksteen 		seq_putc(m, temp_ptr[i]);
2470bfb2374SThiebaud Weksteen 
2480bfb2374SThiebaud Weksteen 	return 0;
2490bfb2374SThiebaud Weksteen 
2500bfb2374SThiebaud Weksteen }
2510bfb2374SThiebaud Weksteen 
2529b01b535SThiebaud Weksteen static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
2530bfb2374SThiebaud Weksteen {
2540bfb2374SThiebaud Weksteen 	char *eventname;
2550bfb2374SThiebaud Weksteen 	struct tcpa_event *event = v;
2560bfb2374SThiebaud Weksteen 	unsigned char *event_entry =
2570bfb2374SThiebaud Weksteen 	    (unsigned char *)(v + sizeof(struct tcpa_event));
2580bfb2374SThiebaud Weksteen 
2590bfb2374SThiebaud Weksteen 	eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
2600bfb2374SThiebaud Weksteen 	if (!eventname) {
2610bfb2374SThiebaud Weksteen 		printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
2620bfb2374SThiebaud Weksteen 		       __func__);
2630bfb2374SThiebaud Weksteen 		return -EFAULT;
2640bfb2374SThiebaud Weksteen 	}
2650bfb2374SThiebaud Weksteen 
2660bfb2374SThiebaud Weksteen 	/* 1st: PCR */
2670bfb2374SThiebaud Weksteen 	seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
2680bfb2374SThiebaud Weksteen 
2690bfb2374SThiebaud Weksteen 	/* 2nd: SHA1 */
2700bfb2374SThiebaud Weksteen 	seq_printf(m, "%20phN", event->pcr_value);
2710bfb2374SThiebaud Weksteen 
2720bfb2374SThiebaud Weksteen 	/* 3rd: event type identifier */
2730bfb2374SThiebaud Weksteen 	seq_printf(m, " %02x", do_endian_conversion(event->event_type));
2740bfb2374SThiebaud Weksteen 
275*df333d05SColin Ian King 	get_event_name(eventname, event, event_entry);
2760bfb2374SThiebaud Weksteen 
2770bfb2374SThiebaud Weksteen 	/* 4th: eventname <= max + \'0' delimiter */
2780bfb2374SThiebaud Weksteen 	seq_printf(m, " %s\n", eventname);
2790bfb2374SThiebaud Weksteen 
2800bfb2374SThiebaud Weksteen 	kfree(eventname);
2810bfb2374SThiebaud Weksteen 	return 0;
2820bfb2374SThiebaud Weksteen }
2830bfb2374SThiebaud Weksteen 
2849b01b535SThiebaud Weksteen const struct seq_operations tpm1_ascii_b_measurements_seqops = {
2859b01b535SThiebaud Weksteen 	.start = tpm1_bios_measurements_start,
2869b01b535SThiebaud Weksteen 	.next = tpm1_bios_measurements_next,
2879b01b535SThiebaud Weksteen 	.stop = tpm1_bios_measurements_stop,
2889b01b535SThiebaud Weksteen 	.show = tpm1_ascii_bios_measurements_show,
2890bfb2374SThiebaud Weksteen };
2900bfb2374SThiebaud Weksteen 
2919b01b535SThiebaud Weksteen const struct seq_operations tpm1_binary_b_measurements_seqops = {
2929b01b535SThiebaud Weksteen 	.start = tpm1_bios_measurements_start,
2939b01b535SThiebaud Weksteen 	.next = tpm1_bios_measurements_next,
2949b01b535SThiebaud Weksteen 	.stop = tpm1_bios_measurements_stop,
2959b01b535SThiebaud Weksteen 	.show = tpm1_binary_bios_measurements_show,
2960bfb2374SThiebaud Weksteen };
297