18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2005, 2012 IBM Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci *	Kent Yoder <key@linux.vnet.ibm.com>
78c2ecf20Sopenharmony_ci *	Seiji Munetoh <munetoh@jp.ibm.com>
88c2ecf20Sopenharmony_ci *	Stefan Berger <stefanb@us.ibm.com>
98c2ecf20Sopenharmony_ci *	Reiner Sailer <sailer@watson.ibm.com>
108c2ecf20Sopenharmony_ci *	Kylene Hall <kjhall@us.ibm.com>
118c2ecf20Sopenharmony_ci *	Nayna Jain <nayna@linux.vnet.ibm.com>
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Maintained by: <tpmdd-devel@lists.sourceforge.net>
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * Access to the event log created by a system's firmware / BIOS
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
198c2ecf20Sopenharmony_ci#include <linux/efi.h>
208c2ecf20Sopenharmony_ci#include <linux/fs.h>
218c2ecf20Sopenharmony_ci#include <linux/security.h>
228c2ecf20Sopenharmony_ci#include <linux/module.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/tpm_eventlog.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "../tpm.h"
278c2ecf20Sopenharmony_ci#include "common.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic const char* tcpa_event_type_strings[] = {
318c2ecf20Sopenharmony_ci	"PREBOOT",
328c2ecf20Sopenharmony_ci	"POST CODE",
338c2ecf20Sopenharmony_ci	"",
348c2ecf20Sopenharmony_ci	"NO ACTION",
358c2ecf20Sopenharmony_ci	"SEPARATOR",
368c2ecf20Sopenharmony_ci	"ACTION",
378c2ecf20Sopenharmony_ci	"EVENT TAG",
388c2ecf20Sopenharmony_ci	"S-CRTM Contents",
398c2ecf20Sopenharmony_ci	"S-CRTM Version",
408c2ecf20Sopenharmony_ci	"CPU Microcode",
418c2ecf20Sopenharmony_ci	"Platform Config Flags",
428c2ecf20Sopenharmony_ci	"Table of Devices",
438c2ecf20Sopenharmony_ci	"Compact Hash",
448c2ecf20Sopenharmony_ci	"IPL",
458c2ecf20Sopenharmony_ci	"IPL Partition Data",
468c2ecf20Sopenharmony_ci	"Non-Host Code",
478c2ecf20Sopenharmony_ci	"Non-Host Config",
488c2ecf20Sopenharmony_ci	"Non-Host Info"
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const char* tcpa_pc_event_id_strings[] = {
528c2ecf20Sopenharmony_ci	"",
538c2ecf20Sopenharmony_ci	"SMBIOS",
548c2ecf20Sopenharmony_ci	"BIS Certificate",
558c2ecf20Sopenharmony_ci	"POST BIOS ",
568c2ecf20Sopenharmony_ci	"ESCD ",
578c2ecf20Sopenharmony_ci	"CMOS",
588c2ecf20Sopenharmony_ci	"NVRAM",
598c2ecf20Sopenharmony_ci	"Option ROM",
608c2ecf20Sopenharmony_ci	"Option ROM config",
618c2ecf20Sopenharmony_ci	"",
628c2ecf20Sopenharmony_ci	"Option ROM microcode ",
638c2ecf20Sopenharmony_ci	"S-CRTM Version",
648c2ecf20Sopenharmony_ci	"S-CRTM Contents ",
658c2ecf20Sopenharmony_ci	"POST Contents ",
668c2ecf20Sopenharmony_ci	"Table of Devices",
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* returns pointer to start of pos. entry of tcg log */
708c2ecf20Sopenharmony_cistatic void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	loff_t i = 0;
738c2ecf20Sopenharmony_ci	struct tpm_chip *chip = m->private;
748c2ecf20Sopenharmony_ci	struct tpm_bios_log *log = &chip->log;
758c2ecf20Sopenharmony_ci	void *addr = log->bios_event_log;
768c2ecf20Sopenharmony_ci	void *limit = log->bios_event_log_end;
778c2ecf20Sopenharmony_ci	struct tcpa_event *event;
788c2ecf20Sopenharmony_ci	u32 converted_event_size;
798c2ecf20Sopenharmony_ci	u32 converted_event_type;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* read over *pos measurements */
828c2ecf20Sopenharmony_ci	do {
838c2ecf20Sopenharmony_ci		event = addr;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		/* check if current entry is valid */
868c2ecf20Sopenharmony_ci		if (addr + sizeof(struct tcpa_event) > limit)
878c2ecf20Sopenharmony_ci			return NULL;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		converted_event_size =
908c2ecf20Sopenharmony_ci		    do_endian_conversion(event->event_size);
918c2ecf20Sopenharmony_ci		converted_event_type =
928c2ecf20Sopenharmony_ci		    do_endian_conversion(event->event_type);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		if (((converted_event_type == 0) && (converted_event_size == 0))
958c2ecf20Sopenharmony_ci		    || ((addr + sizeof(struct tcpa_event) + converted_event_size)
968c2ecf20Sopenharmony_ci			> limit))
978c2ecf20Sopenharmony_ci			return NULL;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		if (i++ == *pos)
1008c2ecf20Sopenharmony_ci			break;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		addr += (sizeof(struct tcpa_event) + converted_event_size);
1038c2ecf20Sopenharmony_ci	} while (1);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return addr;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
1098c2ecf20Sopenharmony_ci					loff_t *pos)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct tcpa_event *event = v;
1128c2ecf20Sopenharmony_ci	struct tpm_chip *chip = m->private;
1138c2ecf20Sopenharmony_ci	struct tpm_bios_log *log = &chip->log;
1148c2ecf20Sopenharmony_ci	void *limit = log->bios_event_log_end;
1158c2ecf20Sopenharmony_ci	u32 converted_event_size;
1168c2ecf20Sopenharmony_ci	u32 converted_event_type;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	(*pos)++;
1198c2ecf20Sopenharmony_ci	converted_event_size = do_endian_conversion(event->event_size);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	v += sizeof(struct tcpa_event) + converted_event_size;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* now check if current entry is valid */
1248c2ecf20Sopenharmony_ci	if ((v + sizeof(struct tcpa_event)) > limit)
1258c2ecf20Sopenharmony_ci		return NULL;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	event = v;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	converted_event_size = do_endian_conversion(event->event_size);
1308c2ecf20Sopenharmony_ci	converted_event_type = do_endian_conversion(event->event_type);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (((converted_event_type == 0) && (converted_event_size == 0)) ||
1338c2ecf20Sopenharmony_ci	    ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
1348c2ecf20Sopenharmony_ci		return NULL;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return v;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic void tpm1_bios_measurements_stop(struct seq_file *m, void *v)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int get_event_name(char *dest, struct tcpa_event *event,
1448c2ecf20Sopenharmony_ci			unsigned char * event_entry)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	const char *name = "";
1478c2ecf20Sopenharmony_ci	/* 41 so there is room for 40 data and 1 nul */
1488c2ecf20Sopenharmony_ci	char data[41] = "";
1498c2ecf20Sopenharmony_ci	int i, n_len = 0, d_len = 0;
1508c2ecf20Sopenharmony_ci	struct tcpa_pc_event *pc_event;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	switch (do_endian_conversion(event->event_type)) {
1538c2ecf20Sopenharmony_ci	case PREBOOT:
1548c2ecf20Sopenharmony_ci	case POST_CODE:
1558c2ecf20Sopenharmony_ci	case UNUSED:
1568c2ecf20Sopenharmony_ci	case NO_ACTION:
1578c2ecf20Sopenharmony_ci	case SCRTM_CONTENTS:
1588c2ecf20Sopenharmony_ci	case SCRTM_VERSION:
1598c2ecf20Sopenharmony_ci	case CPU_MICROCODE:
1608c2ecf20Sopenharmony_ci	case PLATFORM_CONFIG_FLAGS:
1618c2ecf20Sopenharmony_ci	case TABLE_OF_DEVICES:
1628c2ecf20Sopenharmony_ci	case COMPACT_HASH:
1638c2ecf20Sopenharmony_ci	case IPL:
1648c2ecf20Sopenharmony_ci	case IPL_PARTITION_DATA:
1658c2ecf20Sopenharmony_ci	case NONHOST_CODE:
1668c2ecf20Sopenharmony_ci	case NONHOST_CONFIG:
1678c2ecf20Sopenharmony_ci	case NONHOST_INFO:
1688c2ecf20Sopenharmony_ci		name = tcpa_event_type_strings[do_endian_conversion
1698c2ecf20Sopenharmony_ci						(event->event_type)];
1708c2ecf20Sopenharmony_ci		n_len = strlen(name);
1718c2ecf20Sopenharmony_ci		break;
1728c2ecf20Sopenharmony_ci	case SEPARATOR:
1738c2ecf20Sopenharmony_ci	case ACTION:
1748c2ecf20Sopenharmony_ci		if (MAX_TEXT_EVENT >
1758c2ecf20Sopenharmony_ci		    do_endian_conversion(event->event_size)) {
1768c2ecf20Sopenharmony_ci			name = event_entry;
1778c2ecf20Sopenharmony_ci			n_len = do_endian_conversion(event->event_size);
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci		break;
1808c2ecf20Sopenharmony_ci	case EVENT_TAG:
1818c2ecf20Sopenharmony_ci		pc_event = (struct tcpa_pc_event *)event_entry;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		/* ToDo Row data -> Base64 */
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		switch (do_endian_conversion(pc_event->event_id)) {
1868c2ecf20Sopenharmony_ci		case SMBIOS:
1878c2ecf20Sopenharmony_ci		case BIS_CERT:
1888c2ecf20Sopenharmony_ci		case CMOS:
1898c2ecf20Sopenharmony_ci		case NVRAM:
1908c2ecf20Sopenharmony_ci		case OPTION_ROM_EXEC:
1918c2ecf20Sopenharmony_ci		case OPTION_ROM_CONFIG:
1928c2ecf20Sopenharmony_ci		case S_CRTM_VERSION:
1938c2ecf20Sopenharmony_ci			name = tcpa_pc_event_id_strings[do_endian_conversion
1948c2ecf20Sopenharmony_ci							(pc_event->event_id)];
1958c2ecf20Sopenharmony_ci			n_len = strlen(name);
1968c2ecf20Sopenharmony_ci			break;
1978c2ecf20Sopenharmony_ci		/* hash data */
1988c2ecf20Sopenharmony_ci		case POST_BIOS_ROM:
1998c2ecf20Sopenharmony_ci		case ESCD:
2008c2ecf20Sopenharmony_ci		case OPTION_ROM_MICROCODE:
2018c2ecf20Sopenharmony_ci		case S_CRTM_CONTENTS:
2028c2ecf20Sopenharmony_ci		case POST_CONTENTS:
2038c2ecf20Sopenharmony_ci			name = tcpa_pc_event_id_strings[do_endian_conversion
2048c2ecf20Sopenharmony_ci							(pc_event->event_id)];
2058c2ecf20Sopenharmony_ci			n_len = strlen(name);
2068c2ecf20Sopenharmony_ci			for (i = 0; i < 20; i++)
2078c2ecf20Sopenharmony_ci				d_len += sprintf(&data[2*i], "%02x",
2088c2ecf20Sopenharmony_ci						pc_event->event_data[i]);
2098c2ecf20Sopenharmony_ci			break;
2108c2ecf20Sopenharmony_ci		default:
2118c2ecf20Sopenharmony_ci			break;
2128c2ecf20Sopenharmony_ci		}
2138c2ecf20Sopenharmony_ci	default:
2148c2ecf20Sopenharmony_ci		break;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
2188c2ecf20Sopenharmony_ci			n_len, name, d_len, data);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct tcpa_event *event = v;
2258c2ecf20Sopenharmony_ci	struct tcpa_event temp_event;
2268c2ecf20Sopenharmony_ci	char *temp_ptr;
2278c2ecf20Sopenharmony_ci	int i;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	memcpy(&temp_event, event, sizeof(struct tcpa_event));
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* convert raw integers for endianness */
2328c2ecf20Sopenharmony_ci	temp_event.pcr_index = do_endian_conversion(event->pcr_index);
2338c2ecf20Sopenharmony_ci	temp_event.event_type = do_endian_conversion(event->event_type);
2348c2ecf20Sopenharmony_ci	temp_event.event_size = do_endian_conversion(event->event_size);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	temp_ptr = (char *) &temp_event;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
2398c2ecf20Sopenharmony_ci		seq_putc(m, temp_ptr[i]);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	temp_ptr = (char *) v;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	for (i = (sizeof(struct tcpa_event) - 1);
2448c2ecf20Sopenharmony_ci	     i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
2458c2ecf20Sopenharmony_ci		seq_putc(m, temp_ptr[i]);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	int len = 0;
2548c2ecf20Sopenharmony_ci	char *eventname;
2558c2ecf20Sopenharmony_ci	struct tcpa_event *event = v;
2568c2ecf20Sopenharmony_ci	unsigned char *event_entry =
2578c2ecf20Sopenharmony_ci	    (unsigned char *)(v + sizeof(struct tcpa_event));
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
2608c2ecf20Sopenharmony_ci	if (!eventname) {
2618c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
2628c2ecf20Sopenharmony_ci		       __func__);
2638c2ecf20Sopenharmony_ci		return -EFAULT;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/* 1st: PCR */
2678c2ecf20Sopenharmony_ci	seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* 2nd: SHA1 */
2708c2ecf20Sopenharmony_ci	seq_printf(m, "%20phN", event->pcr_value);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* 3rd: event type identifier */
2738c2ecf20Sopenharmony_ci	seq_printf(m, " %02x", do_endian_conversion(event->event_type));
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	len += get_event_name(eventname, event, event_entry);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* 4th: eventname <= max + \'0' delimiter */
2788c2ecf20Sopenharmony_ci	seq_printf(m, " %s\n", eventname);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	kfree(eventname);
2818c2ecf20Sopenharmony_ci	return 0;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ciconst struct seq_operations tpm1_ascii_b_measurements_seqops = {
2858c2ecf20Sopenharmony_ci	.start = tpm1_bios_measurements_start,
2868c2ecf20Sopenharmony_ci	.next = tpm1_bios_measurements_next,
2878c2ecf20Sopenharmony_ci	.stop = tpm1_bios_measurements_stop,
2888c2ecf20Sopenharmony_ci	.show = tpm1_ascii_bios_measurements_show,
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ciconst struct seq_operations tpm1_binary_b_measurements_seqops = {
2928c2ecf20Sopenharmony_ci	.start = tpm1_bios_measurements_start,
2938c2ecf20Sopenharmony_ci	.next = tpm1_bios_measurements_next,
2948c2ecf20Sopenharmony_ci	.stop = tpm1_bios_measurements_stop,
2958c2ecf20Sopenharmony_ci	.show = tpm1_binary_bios_measurements_show,
2968c2ecf20Sopenharmony_ci};
297