162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2005, 2012 IBM Corporation
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Authors:
662306a36Sopenharmony_ci *	Kent Yoder <key@linux.vnet.ibm.com>
762306a36Sopenharmony_ci *	Seiji Munetoh <munetoh@jp.ibm.com>
862306a36Sopenharmony_ci *	Stefan Berger <stefanb@us.ibm.com>
962306a36Sopenharmony_ci *	Reiner Sailer <sailer@watson.ibm.com>
1062306a36Sopenharmony_ci *	Kylene Hall <kjhall@us.ibm.com>
1162306a36Sopenharmony_ci *	Nayna Jain <nayna@linux.vnet.ibm.com>
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Maintained by: <tpmdd-devel@lists.sourceforge.net>
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Access to the event log created by a system's firmware / BIOS
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/seq_file.h>
1962306a36Sopenharmony_ci#include <linux/efi.h>
2062306a36Sopenharmony_ci#include <linux/fs.h>
2162306a36Sopenharmony_ci#include <linux/security.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/slab.h>
2462306a36Sopenharmony_ci#include <linux/tpm_eventlog.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "../tpm.h"
2762306a36Sopenharmony_ci#include "common.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const char* tcpa_event_type_strings[] = {
3162306a36Sopenharmony_ci	"PREBOOT",
3262306a36Sopenharmony_ci	"POST CODE",
3362306a36Sopenharmony_ci	"",
3462306a36Sopenharmony_ci	"NO ACTION",
3562306a36Sopenharmony_ci	"SEPARATOR",
3662306a36Sopenharmony_ci	"ACTION",
3762306a36Sopenharmony_ci	"EVENT TAG",
3862306a36Sopenharmony_ci	"S-CRTM Contents",
3962306a36Sopenharmony_ci	"S-CRTM Version",
4062306a36Sopenharmony_ci	"CPU Microcode",
4162306a36Sopenharmony_ci	"Platform Config Flags",
4262306a36Sopenharmony_ci	"Table of Devices",
4362306a36Sopenharmony_ci	"Compact Hash",
4462306a36Sopenharmony_ci	"IPL",
4562306a36Sopenharmony_ci	"IPL Partition Data",
4662306a36Sopenharmony_ci	"Non-Host Code",
4762306a36Sopenharmony_ci	"Non-Host Config",
4862306a36Sopenharmony_ci	"Non-Host Info"
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const char* tcpa_pc_event_id_strings[] = {
5262306a36Sopenharmony_ci	"",
5362306a36Sopenharmony_ci	"SMBIOS",
5462306a36Sopenharmony_ci	"BIS Certificate",
5562306a36Sopenharmony_ci	"POST BIOS ",
5662306a36Sopenharmony_ci	"ESCD ",
5762306a36Sopenharmony_ci	"CMOS",
5862306a36Sopenharmony_ci	"NVRAM",
5962306a36Sopenharmony_ci	"Option ROM",
6062306a36Sopenharmony_ci	"Option ROM config",
6162306a36Sopenharmony_ci	"",
6262306a36Sopenharmony_ci	"Option ROM microcode ",
6362306a36Sopenharmony_ci	"S-CRTM Version",
6462306a36Sopenharmony_ci	"S-CRTM Contents ",
6562306a36Sopenharmony_ci	"POST Contents ",
6662306a36Sopenharmony_ci	"Table of Devices",
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* returns pointer to start of pos. entry of tcg log */
7062306a36Sopenharmony_cistatic void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	loff_t i = 0;
7362306a36Sopenharmony_ci	struct tpm_chip *chip = m->private;
7462306a36Sopenharmony_ci	struct tpm_bios_log *log = &chip->log;
7562306a36Sopenharmony_ci	void *addr = log->bios_event_log;
7662306a36Sopenharmony_ci	void *limit = log->bios_event_log_end;
7762306a36Sopenharmony_ci	struct tcpa_event *event;
7862306a36Sopenharmony_ci	u32 converted_event_size;
7962306a36Sopenharmony_ci	u32 converted_event_type;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* read over *pos measurements */
8262306a36Sopenharmony_ci	do {
8362306a36Sopenharmony_ci		event = addr;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		/* check if current entry is valid */
8662306a36Sopenharmony_ci		if (addr + sizeof(struct tcpa_event) > limit)
8762306a36Sopenharmony_ci			return NULL;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		converted_event_size =
9062306a36Sopenharmony_ci		    do_endian_conversion(event->event_size);
9162306a36Sopenharmony_ci		converted_event_type =
9262306a36Sopenharmony_ci		    do_endian_conversion(event->event_type);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		if (((converted_event_type == 0) && (converted_event_size == 0))
9562306a36Sopenharmony_ci		    || ((addr + sizeof(struct tcpa_event) + converted_event_size)
9662306a36Sopenharmony_ci			> limit))
9762306a36Sopenharmony_ci			return NULL;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		if (i++ == *pos)
10062306a36Sopenharmony_ci			break;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		addr += (sizeof(struct tcpa_event) + converted_event_size);
10362306a36Sopenharmony_ci	} while (1);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	return addr;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
10962306a36Sopenharmony_ci					loff_t *pos)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct tcpa_event *event = v;
11262306a36Sopenharmony_ci	struct tpm_chip *chip = m->private;
11362306a36Sopenharmony_ci	struct tpm_bios_log *log = &chip->log;
11462306a36Sopenharmony_ci	void *limit = log->bios_event_log_end;
11562306a36Sopenharmony_ci	u32 converted_event_size;
11662306a36Sopenharmony_ci	u32 converted_event_type;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	(*pos)++;
11962306a36Sopenharmony_ci	converted_event_size = do_endian_conversion(event->event_size);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	v += sizeof(struct tcpa_event) + converted_event_size;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* now check if current entry is valid */
12462306a36Sopenharmony_ci	if ((v + sizeof(struct tcpa_event)) > limit)
12562306a36Sopenharmony_ci		return NULL;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	event = v;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	converted_event_size = do_endian_conversion(event->event_size);
13062306a36Sopenharmony_ci	converted_event_type = do_endian_conversion(event->event_type);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (((converted_event_type == 0) && (converted_event_size == 0)) ||
13362306a36Sopenharmony_ci	    ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
13462306a36Sopenharmony_ci		return NULL;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return v;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic void tpm1_bios_measurements_stop(struct seq_file *m, void *v)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int get_event_name(char *dest, struct tcpa_event *event,
14462306a36Sopenharmony_ci			unsigned char * event_entry)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	const char *name = "";
14762306a36Sopenharmony_ci	/* 41 so there is room for 40 data and 1 nul */
14862306a36Sopenharmony_ci	char data[41] = "";
14962306a36Sopenharmony_ci	int i, n_len = 0, d_len = 0;
15062306a36Sopenharmony_ci	struct tcpa_pc_event *pc_event;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	switch (do_endian_conversion(event->event_type)) {
15362306a36Sopenharmony_ci	case PREBOOT:
15462306a36Sopenharmony_ci	case POST_CODE:
15562306a36Sopenharmony_ci	case UNUSED:
15662306a36Sopenharmony_ci	case NO_ACTION:
15762306a36Sopenharmony_ci	case SCRTM_CONTENTS:
15862306a36Sopenharmony_ci	case SCRTM_VERSION:
15962306a36Sopenharmony_ci	case CPU_MICROCODE:
16062306a36Sopenharmony_ci	case PLATFORM_CONFIG_FLAGS:
16162306a36Sopenharmony_ci	case TABLE_OF_DEVICES:
16262306a36Sopenharmony_ci	case COMPACT_HASH:
16362306a36Sopenharmony_ci	case IPL:
16462306a36Sopenharmony_ci	case IPL_PARTITION_DATA:
16562306a36Sopenharmony_ci	case NONHOST_CODE:
16662306a36Sopenharmony_ci	case NONHOST_CONFIG:
16762306a36Sopenharmony_ci	case NONHOST_INFO:
16862306a36Sopenharmony_ci		name = tcpa_event_type_strings[do_endian_conversion
16962306a36Sopenharmony_ci						(event->event_type)];
17062306a36Sopenharmony_ci		n_len = strlen(name);
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	case SEPARATOR:
17362306a36Sopenharmony_ci	case ACTION:
17462306a36Sopenharmony_ci		if (MAX_TEXT_EVENT >
17562306a36Sopenharmony_ci		    do_endian_conversion(event->event_size)) {
17662306a36Sopenharmony_ci			name = event_entry;
17762306a36Sopenharmony_ci			n_len = do_endian_conversion(event->event_size);
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	case EVENT_TAG:
18162306a36Sopenharmony_ci		pc_event = (struct tcpa_pc_event *)event_entry;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci		/* ToDo Row data -> Base64 */
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci		switch (do_endian_conversion(pc_event->event_id)) {
18662306a36Sopenharmony_ci		case SMBIOS:
18762306a36Sopenharmony_ci		case BIS_CERT:
18862306a36Sopenharmony_ci		case CMOS:
18962306a36Sopenharmony_ci		case NVRAM:
19062306a36Sopenharmony_ci		case OPTION_ROM_EXEC:
19162306a36Sopenharmony_ci		case OPTION_ROM_CONFIG:
19262306a36Sopenharmony_ci		case S_CRTM_VERSION:
19362306a36Sopenharmony_ci			name = tcpa_pc_event_id_strings[do_endian_conversion
19462306a36Sopenharmony_ci							(pc_event->event_id)];
19562306a36Sopenharmony_ci			n_len = strlen(name);
19662306a36Sopenharmony_ci			break;
19762306a36Sopenharmony_ci		/* hash data */
19862306a36Sopenharmony_ci		case POST_BIOS_ROM:
19962306a36Sopenharmony_ci		case ESCD:
20062306a36Sopenharmony_ci		case OPTION_ROM_MICROCODE:
20162306a36Sopenharmony_ci		case S_CRTM_CONTENTS:
20262306a36Sopenharmony_ci		case POST_CONTENTS:
20362306a36Sopenharmony_ci			name = tcpa_pc_event_id_strings[do_endian_conversion
20462306a36Sopenharmony_ci							(pc_event->event_id)];
20562306a36Sopenharmony_ci			n_len = strlen(name);
20662306a36Sopenharmony_ci			for (i = 0; i < 20; i++)
20762306a36Sopenharmony_ci				d_len += sprintf(&data[2*i], "%02x",
20862306a36Sopenharmony_ci						pc_event->event_data[i]);
20962306a36Sopenharmony_ci			break;
21062306a36Sopenharmony_ci		default:
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci		}
21362306a36Sopenharmony_ci		break;
21462306a36Sopenharmony_ci	default:
21562306a36Sopenharmony_ci		break;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
21962306a36Sopenharmony_ci			n_len, name, d_len, data);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct tcpa_event *event = v;
22662306a36Sopenharmony_ci	struct tcpa_event temp_event;
22762306a36Sopenharmony_ci	char *temp_ptr;
22862306a36Sopenharmony_ci	int i;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	memcpy(&temp_event, event, sizeof(struct tcpa_event));
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* convert raw integers for endianness */
23362306a36Sopenharmony_ci	temp_event.pcr_index = do_endian_conversion(event->pcr_index);
23462306a36Sopenharmony_ci	temp_event.event_type = do_endian_conversion(event->event_type);
23562306a36Sopenharmony_ci	temp_event.event_size = do_endian_conversion(event->event_size);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	temp_ptr = (char *) &temp_event;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
24062306a36Sopenharmony_ci		seq_putc(m, temp_ptr[i]);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	temp_ptr = (char *) v;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	for (i = (sizeof(struct tcpa_event) - 1);
24562306a36Sopenharmony_ci	     i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
24662306a36Sopenharmony_ci		seq_putc(m, temp_ptr[i]);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	char *eventname;
25562306a36Sopenharmony_ci	struct tcpa_event *event = v;
25662306a36Sopenharmony_ci	unsigned char *event_entry =
25762306a36Sopenharmony_ci	    (unsigned char *)(v + sizeof(struct tcpa_event));
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
26062306a36Sopenharmony_ci	if (!eventname) {
26162306a36Sopenharmony_ci		printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
26262306a36Sopenharmony_ci		       __func__);
26362306a36Sopenharmony_ci		return -EFAULT;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* 1st: PCR */
26762306a36Sopenharmony_ci	seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* 2nd: SHA1 */
27062306a36Sopenharmony_ci	seq_printf(m, "%20phN", event->pcr_value);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* 3rd: event type identifier */
27362306a36Sopenharmony_ci	seq_printf(m, " %02x", do_endian_conversion(event->event_type));
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	get_event_name(eventname, event, event_entry);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* 4th: eventname <= max + \'0' delimiter */
27862306a36Sopenharmony_ci	seq_printf(m, " %s\n", eventname);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	kfree(eventname);
28162306a36Sopenharmony_ci	return 0;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ciconst struct seq_operations tpm1_ascii_b_measurements_seqops = {
28562306a36Sopenharmony_ci	.start = tpm1_bios_measurements_start,
28662306a36Sopenharmony_ci	.next = tpm1_bios_measurements_next,
28762306a36Sopenharmony_ci	.stop = tpm1_bios_measurements_stop,
28862306a36Sopenharmony_ci	.show = tpm1_ascii_bios_measurements_show,
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciconst struct seq_operations tpm1_binary_b_measurements_seqops = {
29262306a36Sopenharmony_ci	.start = tpm1_bios_measurements_start,
29362306a36Sopenharmony_ci	.next = tpm1_bios_measurements_next,
29462306a36Sopenharmony_ci	.stop = tpm1_bios_measurements_stop,
29562306a36Sopenharmony_ci	.show = tpm1_binary_bios_measurements_show,
29662306a36Sopenharmony_ci};
297