10bfb2374SThiebaud Weksteen /* 20bfb2374SThiebaud Weksteen * Copyright (C) 2005, 2012 IBM Corporation 30bfb2374SThiebaud Weksteen * 40bfb2374SThiebaud Weksteen * Authors: 50bfb2374SThiebaud Weksteen * Kent Yoder <key@linux.vnet.ibm.com> 60bfb2374SThiebaud Weksteen * Seiji Munetoh <munetoh@jp.ibm.com> 70bfb2374SThiebaud Weksteen * Stefan Berger <stefanb@us.ibm.com> 80bfb2374SThiebaud Weksteen * Reiner Sailer <sailer@watson.ibm.com> 90bfb2374SThiebaud Weksteen * Kylene Hall <kjhall@us.ibm.com> 100bfb2374SThiebaud Weksteen * Nayna Jain <nayna@linux.vnet.ibm.com> 110bfb2374SThiebaud Weksteen * 120bfb2374SThiebaud Weksteen * Maintained by: <tpmdd-devel@lists.sourceforge.net> 130bfb2374SThiebaud Weksteen * 140bfb2374SThiebaud Weksteen * Access to the event log created by a system's firmware / BIOS 150bfb2374SThiebaud Weksteen * 160bfb2374SThiebaud Weksteen * This program is free software; you can redistribute it and/or 170bfb2374SThiebaud Weksteen * modify it under the terms of the GNU General Public License 180bfb2374SThiebaud Weksteen * as published by the Free Software Foundation; either version 190bfb2374SThiebaud Weksteen * 2 of the License, or (at your option) any later version. 200bfb2374SThiebaud Weksteen * 210bfb2374SThiebaud Weksteen */ 220bfb2374SThiebaud Weksteen 230bfb2374SThiebaud Weksteen #include <linux/seq_file.h> 240bfb2374SThiebaud Weksteen #include <linux/efi.h> 250bfb2374SThiebaud Weksteen #include <linux/fs.h> 260bfb2374SThiebaud Weksteen #include <linux/security.h> 270bfb2374SThiebaud Weksteen #include <linux/module.h> 280bfb2374SThiebaud Weksteen #include <linux/slab.h> 290bfb2374SThiebaud Weksteen #include <linux/tpm_eventlog.h> 300bfb2374SThiebaud Weksteen 310bfb2374SThiebaud Weksteen #include "../tpm.h" 32*75d647f5SThiebaud Weksteen #include "common.h" 330bfb2374SThiebaud Weksteen 340bfb2374SThiebaud Weksteen 350bfb2374SThiebaud Weksteen static const char* tcpa_event_type_strings[] = { 360bfb2374SThiebaud Weksteen "PREBOOT", 370bfb2374SThiebaud Weksteen "POST CODE", 380bfb2374SThiebaud Weksteen "", 390bfb2374SThiebaud Weksteen "NO ACTION", 400bfb2374SThiebaud Weksteen "SEPARATOR", 410bfb2374SThiebaud Weksteen "ACTION", 420bfb2374SThiebaud Weksteen "EVENT TAG", 430bfb2374SThiebaud Weksteen "S-CRTM Contents", 440bfb2374SThiebaud Weksteen "S-CRTM Version", 450bfb2374SThiebaud Weksteen "CPU Microcode", 460bfb2374SThiebaud Weksteen "Platform Config Flags", 470bfb2374SThiebaud Weksteen "Table of Devices", 480bfb2374SThiebaud Weksteen "Compact Hash", 490bfb2374SThiebaud Weksteen "IPL", 500bfb2374SThiebaud Weksteen "IPL Partition Data", 510bfb2374SThiebaud Weksteen "Non-Host Code", 520bfb2374SThiebaud Weksteen "Non-Host Config", 530bfb2374SThiebaud Weksteen "Non-Host Info" 540bfb2374SThiebaud Weksteen }; 550bfb2374SThiebaud Weksteen 560bfb2374SThiebaud Weksteen static const char* tcpa_pc_event_id_strings[] = { 570bfb2374SThiebaud Weksteen "", 580bfb2374SThiebaud Weksteen "SMBIOS", 590bfb2374SThiebaud Weksteen "BIS Certificate", 600bfb2374SThiebaud Weksteen "POST BIOS ", 610bfb2374SThiebaud Weksteen "ESCD ", 620bfb2374SThiebaud Weksteen "CMOS", 630bfb2374SThiebaud Weksteen "NVRAM", 640bfb2374SThiebaud Weksteen "Option ROM", 650bfb2374SThiebaud Weksteen "Option ROM config", 660bfb2374SThiebaud Weksteen "", 670bfb2374SThiebaud Weksteen "Option ROM microcode ", 680bfb2374SThiebaud Weksteen "S-CRTM Version", 690bfb2374SThiebaud Weksteen "S-CRTM Contents ", 700bfb2374SThiebaud Weksteen "POST Contents ", 710bfb2374SThiebaud Weksteen "Table of Devices", 720bfb2374SThiebaud Weksteen }; 730bfb2374SThiebaud Weksteen 740bfb2374SThiebaud Weksteen /* returns pointer to start of pos. entry of tcg log */ 759b01b535SThiebaud Weksteen static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos) 760bfb2374SThiebaud Weksteen { 770bfb2374SThiebaud Weksteen loff_t i; 780bfb2374SThiebaud Weksteen struct tpm_chip *chip = m->private; 790bfb2374SThiebaud Weksteen struct tpm_bios_log *log = &chip->log; 800bfb2374SThiebaud Weksteen void *addr = log->bios_event_log; 810bfb2374SThiebaud Weksteen void *limit = log->bios_event_log_end; 820bfb2374SThiebaud Weksteen struct tcpa_event *event; 830bfb2374SThiebaud Weksteen u32 converted_event_size; 840bfb2374SThiebaud Weksteen u32 converted_event_type; 850bfb2374SThiebaud Weksteen 860bfb2374SThiebaud Weksteen 870bfb2374SThiebaud Weksteen /* read over *pos measurements */ 880bfb2374SThiebaud Weksteen for (i = 0; i < *pos; i++) { 890bfb2374SThiebaud Weksteen event = addr; 900bfb2374SThiebaud Weksteen 910bfb2374SThiebaud Weksteen converted_event_size = 920bfb2374SThiebaud Weksteen do_endian_conversion(event->event_size); 930bfb2374SThiebaud Weksteen converted_event_type = 940bfb2374SThiebaud Weksteen do_endian_conversion(event->event_type); 950bfb2374SThiebaud Weksteen 960bfb2374SThiebaud Weksteen if ((addr + sizeof(struct tcpa_event)) < limit) { 970bfb2374SThiebaud Weksteen if ((converted_event_type == 0) && 980bfb2374SThiebaud Weksteen (converted_event_size == 0)) 990bfb2374SThiebaud Weksteen return NULL; 1000bfb2374SThiebaud Weksteen addr += (sizeof(struct tcpa_event) + 1010bfb2374SThiebaud Weksteen converted_event_size); 1020bfb2374SThiebaud Weksteen } 1030bfb2374SThiebaud Weksteen } 1040bfb2374SThiebaud Weksteen 1050bfb2374SThiebaud Weksteen /* now check if current entry is valid */ 1060bfb2374SThiebaud Weksteen if ((addr + sizeof(struct tcpa_event)) >= limit) 1070bfb2374SThiebaud Weksteen return NULL; 1080bfb2374SThiebaud Weksteen 1090bfb2374SThiebaud Weksteen event = addr; 1100bfb2374SThiebaud Weksteen 1110bfb2374SThiebaud Weksteen converted_event_size = do_endian_conversion(event->event_size); 1120bfb2374SThiebaud Weksteen converted_event_type = do_endian_conversion(event->event_type); 1130bfb2374SThiebaud Weksteen 1140bfb2374SThiebaud Weksteen if (((converted_event_type == 0) && (converted_event_size == 0)) 1150bfb2374SThiebaud Weksteen || ((addr + sizeof(struct tcpa_event) + converted_event_size) 1160bfb2374SThiebaud Weksteen >= limit)) 1170bfb2374SThiebaud Weksteen return NULL; 1180bfb2374SThiebaud Weksteen 1190bfb2374SThiebaud Weksteen return addr; 1200bfb2374SThiebaud Weksteen } 1210bfb2374SThiebaud Weksteen 1229b01b535SThiebaud Weksteen static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, 1230bfb2374SThiebaud Weksteen loff_t *pos) 1240bfb2374SThiebaud Weksteen { 1250bfb2374SThiebaud Weksteen struct tcpa_event *event = v; 1260bfb2374SThiebaud Weksteen struct tpm_chip *chip = m->private; 1270bfb2374SThiebaud Weksteen struct tpm_bios_log *log = &chip->log; 1280bfb2374SThiebaud Weksteen void *limit = log->bios_event_log_end; 1290bfb2374SThiebaud Weksteen u32 converted_event_size; 1300bfb2374SThiebaud Weksteen u32 converted_event_type; 1310bfb2374SThiebaud Weksteen 1320bfb2374SThiebaud Weksteen converted_event_size = do_endian_conversion(event->event_size); 1330bfb2374SThiebaud Weksteen 1340bfb2374SThiebaud Weksteen v += sizeof(struct tcpa_event) + converted_event_size; 1350bfb2374SThiebaud Weksteen 1360bfb2374SThiebaud Weksteen /* now check if current entry is valid */ 1370bfb2374SThiebaud Weksteen if ((v + sizeof(struct tcpa_event)) >= limit) 1380bfb2374SThiebaud Weksteen return NULL; 1390bfb2374SThiebaud Weksteen 1400bfb2374SThiebaud Weksteen event = v; 1410bfb2374SThiebaud Weksteen 1420bfb2374SThiebaud Weksteen converted_event_size = do_endian_conversion(event->event_size); 1430bfb2374SThiebaud Weksteen converted_event_type = do_endian_conversion(event->event_type); 1440bfb2374SThiebaud Weksteen 1450bfb2374SThiebaud Weksteen if (((converted_event_type == 0) && (converted_event_size == 0)) || 1460bfb2374SThiebaud Weksteen ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit)) 1470bfb2374SThiebaud Weksteen return NULL; 1480bfb2374SThiebaud Weksteen 1490bfb2374SThiebaud Weksteen (*pos)++; 1500bfb2374SThiebaud Weksteen return v; 1510bfb2374SThiebaud Weksteen } 1520bfb2374SThiebaud Weksteen 1539b01b535SThiebaud Weksteen static void tpm1_bios_measurements_stop(struct seq_file *m, void *v) 1540bfb2374SThiebaud Weksteen { 1550bfb2374SThiebaud Weksteen } 1560bfb2374SThiebaud Weksteen 1570bfb2374SThiebaud Weksteen static int get_event_name(char *dest, struct tcpa_event *event, 1580bfb2374SThiebaud Weksteen unsigned char * event_entry) 1590bfb2374SThiebaud Weksteen { 1600bfb2374SThiebaud Weksteen const char *name = ""; 1610bfb2374SThiebaud Weksteen /* 41 so there is room for 40 data and 1 nul */ 1620bfb2374SThiebaud Weksteen char data[41] = ""; 1630bfb2374SThiebaud Weksteen int i, n_len = 0, d_len = 0; 1640bfb2374SThiebaud Weksteen struct tcpa_pc_event *pc_event; 1650bfb2374SThiebaud Weksteen 1660bfb2374SThiebaud Weksteen switch (do_endian_conversion(event->event_type)) { 1670bfb2374SThiebaud Weksteen case PREBOOT: 1680bfb2374SThiebaud Weksteen case POST_CODE: 1690bfb2374SThiebaud Weksteen case UNUSED: 1700bfb2374SThiebaud Weksteen case NO_ACTION: 1710bfb2374SThiebaud Weksteen case SCRTM_CONTENTS: 1720bfb2374SThiebaud Weksteen case SCRTM_VERSION: 1730bfb2374SThiebaud Weksteen case CPU_MICROCODE: 1740bfb2374SThiebaud Weksteen case PLATFORM_CONFIG_FLAGS: 1750bfb2374SThiebaud Weksteen case TABLE_OF_DEVICES: 1760bfb2374SThiebaud Weksteen case COMPACT_HASH: 1770bfb2374SThiebaud Weksteen case IPL: 1780bfb2374SThiebaud Weksteen case IPL_PARTITION_DATA: 1790bfb2374SThiebaud Weksteen case NONHOST_CODE: 1800bfb2374SThiebaud Weksteen case NONHOST_CONFIG: 1810bfb2374SThiebaud Weksteen case NONHOST_INFO: 1820bfb2374SThiebaud Weksteen name = tcpa_event_type_strings[do_endian_conversion 1830bfb2374SThiebaud Weksteen (event->event_type)]; 1840bfb2374SThiebaud Weksteen n_len = strlen(name); 1850bfb2374SThiebaud Weksteen break; 1860bfb2374SThiebaud Weksteen case SEPARATOR: 1870bfb2374SThiebaud Weksteen case ACTION: 1880bfb2374SThiebaud Weksteen if (MAX_TEXT_EVENT > 1890bfb2374SThiebaud Weksteen do_endian_conversion(event->event_size)) { 1900bfb2374SThiebaud Weksteen name = event_entry; 1910bfb2374SThiebaud Weksteen n_len = do_endian_conversion(event->event_size); 1920bfb2374SThiebaud Weksteen } 1930bfb2374SThiebaud Weksteen break; 1940bfb2374SThiebaud Weksteen case EVENT_TAG: 1950bfb2374SThiebaud Weksteen pc_event = (struct tcpa_pc_event *)event_entry; 1960bfb2374SThiebaud Weksteen 1970bfb2374SThiebaud Weksteen /* ToDo Row data -> Base64 */ 1980bfb2374SThiebaud Weksteen 1990bfb2374SThiebaud Weksteen switch (do_endian_conversion(pc_event->event_id)) { 2000bfb2374SThiebaud Weksteen case SMBIOS: 2010bfb2374SThiebaud Weksteen case BIS_CERT: 2020bfb2374SThiebaud Weksteen case CMOS: 2030bfb2374SThiebaud Weksteen case NVRAM: 2040bfb2374SThiebaud Weksteen case OPTION_ROM_EXEC: 2050bfb2374SThiebaud Weksteen case OPTION_ROM_CONFIG: 2060bfb2374SThiebaud Weksteen case S_CRTM_VERSION: 2070bfb2374SThiebaud Weksteen name = tcpa_pc_event_id_strings[do_endian_conversion 2080bfb2374SThiebaud Weksteen (pc_event->event_id)]; 2090bfb2374SThiebaud Weksteen n_len = strlen(name); 2100bfb2374SThiebaud Weksteen break; 2110bfb2374SThiebaud Weksteen /* hash data */ 2120bfb2374SThiebaud Weksteen case POST_BIOS_ROM: 2130bfb2374SThiebaud Weksteen case ESCD: 2140bfb2374SThiebaud Weksteen case OPTION_ROM_MICROCODE: 2150bfb2374SThiebaud Weksteen case S_CRTM_CONTENTS: 2160bfb2374SThiebaud Weksteen case POST_CONTENTS: 2170bfb2374SThiebaud Weksteen name = tcpa_pc_event_id_strings[do_endian_conversion 2180bfb2374SThiebaud Weksteen (pc_event->event_id)]; 2190bfb2374SThiebaud Weksteen n_len = strlen(name); 2200bfb2374SThiebaud Weksteen for (i = 0; i < 20; i++) 2210bfb2374SThiebaud Weksteen d_len += sprintf(&data[2*i], "%02x", 2220bfb2374SThiebaud Weksteen pc_event->event_data[i]); 2230bfb2374SThiebaud Weksteen break; 2240bfb2374SThiebaud Weksteen default: 2250bfb2374SThiebaud Weksteen break; 2260bfb2374SThiebaud Weksteen } 2270bfb2374SThiebaud Weksteen default: 2280bfb2374SThiebaud Weksteen break; 2290bfb2374SThiebaud Weksteen } 2300bfb2374SThiebaud Weksteen 2310bfb2374SThiebaud Weksteen return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]", 2320bfb2374SThiebaud Weksteen n_len, name, d_len, data); 2330bfb2374SThiebaud Weksteen 2340bfb2374SThiebaud Weksteen } 2350bfb2374SThiebaud Weksteen 2369b01b535SThiebaud Weksteen static int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v) 2370bfb2374SThiebaud Weksteen { 2380bfb2374SThiebaud Weksteen struct tcpa_event *event = v; 2390bfb2374SThiebaud Weksteen struct tcpa_event temp_event; 2400bfb2374SThiebaud Weksteen char *temp_ptr; 2410bfb2374SThiebaud Weksteen int i; 2420bfb2374SThiebaud Weksteen 2430bfb2374SThiebaud Weksteen memcpy(&temp_event, event, sizeof(struct tcpa_event)); 2440bfb2374SThiebaud Weksteen 2450bfb2374SThiebaud Weksteen /* convert raw integers for endianness */ 2460bfb2374SThiebaud Weksteen temp_event.pcr_index = do_endian_conversion(event->pcr_index); 2470bfb2374SThiebaud Weksteen temp_event.event_type = do_endian_conversion(event->event_type); 2480bfb2374SThiebaud Weksteen temp_event.event_size = do_endian_conversion(event->event_size); 2490bfb2374SThiebaud Weksteen 2500bfb2374SThiebaud Weksteen temp_ptr = (char *) &temp_event; 2510bfb2374SThiebaud Weksteen 2520bfb2374SThiebaud Weksteen for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++) 2530bfb2374SThiebaud Weksteen seq_putc(m, temp_ptr[i]); 2540bfb2374SThiebaud Weksteen 2550bfb2374SThiebaud Weksteen temp_ptr = (char *) v; 2560bfb2374SThiebaud Weksteen 2570bfb2374SThiebaud Weksteen for (i = (sizeof(struct tcpa_event) - 1); 2580bfb2374SThiebaud Weksteen i < (sizeof(struct tcpa_event) + temp_event.event_size); i++) 2590bfb2374SThiebaud Weksteen seq_putc(m, temp_ptr[i]); 2600bfb2374SThiebaud Weksteen 2610bfb2374SThiebaud Weksteen return 0; 2620bfb2374SThiebaud Weksteen 2630bfb2374SThiebaud Weksteen } 2640bfb2374SThiebaud Weksteen 2659b01b535SThiebaud Weksteen static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v) 2660bfb2374SThiebaud Weksteen { 2670bfb2374SThiebaud Weksteen int len = 0; 2680bfb2374SThiebaud Weksteen char *eventname; 2690bfb2374SThiebaud Weksteen struct tcpa_event *event = v; 2700bfb2374SThiebaud Weksteen unsigned char *event_entry = 2710bfb2374SThiebaud Weksteen (unsigned char *)(v + sizeof(struct tcpa_event)); 2720bfb2374SThiebaud Weksteen 2730bfb2374SThiebaud Weksteen eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); 2740bfb2374SThiebaud Weksteen if (!eventname) { 2750bfb2374SThiebaud Weksteen printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", 2760bfb2374SThiebaud Weksteen __func__); 2770bfb2374SThiebaud Weksteen return -EFAULT; 2780bfb2374SThiebaud Weksteen } 2790bfb2374SThiebaud Weksteen 2800bfb2374SThiebaud Weksteen /* 1st: PCR */ 2810bfb2374SThiebaud Weksteen seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index)); 2820bfb2374SThiebaud Weksteen 2830bfb2374SThiebaud Weksteen /* 2nd: SHA1 */ 2840bfb2374SThiebaud Weksteen seq_printf(m, "%20phN", event->pcr_value); 2850bfb2374SThiebaud Weksteen 2860bfb2374SThiebaud Weksteen /* 3rd: event type identifier */ 2870bfb2374SThiebaud Weksteen seq_printf(m, " %02x", do_endian_conversion(event->event_type)); 2880bfb2374SThiebaud Weksteen 2890bfb2374SThiebaud Weksteen len += get_event_name(eventname, event, event_entry); 2900bfb2374SThiebaud Weksteen 2910bfb2374SThiebaud Weksteen /* 4th: eventname <= max + \'0' delimiter */ 2920bfb2374SThiebaud Weksteen seq_printf(m, " %s\n", eventname); 2930bfb2374SThiebaud Weksteen 2940bfb2374SThiebaud Weksteen kfree(eventname); 2950bfb2374SThiebaud Weksteen return 0; 2960bfb2374SThiebaud Weksteen } 2970bfb2374SThiebaud Weksteen 2989b01b535SThiebaud Weksteen const struct seq_operations tpm1_ascii_b_measurements_seqops = { 2999b01b535SThiebaud Weksteen .start = tpm1_bios_measurements_start, 3009b01b535SThiebaud Weksteen .next = tpm1_bios_measurements_next, 3019b01b535SThiebaud Weksteen .stop = tpm1_bios_measurements_stop, 3029b01b535SThiebaud Weksteen .show = tpm1_ascii_bios_measurements_show, 3030bfb2374SThiebaud Weksteen }; 3040bfb2374SThiebaud Weksteen 3059b01b535SThiebaud Weksteen const struct seq_operations tpm1_binary_b_measurements_seqops = { 3069b01b535SThiebaud Weksteen .start = tpm1_bios_measurements_start, 3079b01b535SThiebaud Weksteen .next = tpm1_bios_measurements_next, 3089b01b535SThiebaud Weksteen .stop = tpm1_bios_measurements_stop, 3099b01b535SThiebaud Weksteen .show = tpm1_binary_bios_measurements_show, 3100bfb2374SThiebaud Weksteen }; 311