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