linux/drivers/char/tpm/eventlog/tpm1.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2005, 2012 IBM Corporation
   4 *
   5 * Authors:
   6 *      Kent Yoder <key@linux.vnet.ibm.com>
   7 *      Seiji Munetoh <munetoh@jp.ibm.com>
   8 *      Stefan Berger <stefanb@us.ibm.com>
   9 *      Reiner Sailer <sailer@watson.ibm.com>
  10 *      Kylene Hall <kjhall@us.ibm.com>
  11 *      Nayna Jain <nayna@linux.vnet.ibm.com>
  12 *
  13 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  14 *
  15 * Access to the event log created by a system's firmware / BIOS
  16 */
  17
  18#include <linux/seq_file.h>
  19#include <linux/efi.h>
  20#include <linux/fs.h>
  21#include <linux/security.h>
  22#include <linux/module.h>
  23#include <linux/slab.h>
  24#include <linux/tpm_eventlog.h>
  25
  26#include "../tpm.h"
  27#include "common.h"
  28
  29
  30static const char* tcpa_event_type_strings[] = {
  31        "PREBOOT",
  32        "POST CODE",
  33        "",
  34        "NO ACTION",
  35        "SEPARATOR",
  36        "ACTION",
  37        "EVENT TAG",
  38        "S-CRTM Contents",
  39        "S-CRTM Version",
  40        "CPU Microcode",
  41        "Platform Config Flags",
  42        "Table of Devices",
  43        "Compact Hash",
  44        "IPL",
  45        "IPL Partition Data",
  46        "Non-Host Code",
  47        "Non-Host Config",
  48        "Non-Host Info"
  49};
  50
  51static const char* tcpa_pc_event_id_strings[] = {
  52        "",
  53        "SMBIOS",
  54        "BIS Certificate",
  55        "POST BIOS ",
  56        "ESCD ",
  57        "CMOS",
  58        "NVRAM",
  59        "Option ROM",
  60        "Option ROM config",
  61        "",
  62        "Option ROM microcode ",
  63        "S-CRTM Version",
  64        "S-CRTM Contents ",
  65        "POST Contents ",
  66        "Table of Devices",
  67};
  68
  69/* returns pointer to start of pos. entry of tcg log */
  70static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
  71{
  72        loff_t i = 0;
  73        struct tpm_chip *chip = m->private;
  74        struct tpm_bios_log *log = &chip->log;
  75        void *addr = log->bios_event_log;
  76        void *limit = log->bios_event_log_end;
  77        struct tcpa_event *event;
  78        u32 converted_event_size;
  79        u32 converted_event_type;
  80
  81        /* read over *pos measurements */
  82        do {
  83                event = addr;
  84
  85                /* check if current entry is valid */
  86                if (addr + sizeof(struct tcpa_event) > limit)
  87                        return NULL;
  88
  89                converted_event_size =
  90                    do_endian_conversion(event->event_size);
  91                converted_event_type =
  92                    do_endian_conversion(event->event_type);
  93
  94                if (((converted_event_type == 0) && (converted_event_size == 0))
  95                    || ((addr + sizeof(struct tcpa_event) + converted_event_size)
  96                        > limit))
  97                        return NULL;
  98
  99                if (i++ == *pos)
 100                        break;
 101
 102                addr += (sizeof(struct tcpa_event) + converted_event_size);
 103        } while (1);
 104
 105        return addr;
 106}
 107
 108static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
 109                                        loff_t *pos)
 110{
 111        struct tcpa_event *event = v;
 112        struct tpm_chip *chip = m->private;
 113        struct tpm_bios_log *log = &chip->log;
 114        void *limit = log->bios_event_log_end;
 115        u32 converted_event_size;
 116        u32 converted_event_type;
 117
 118        converted_event_size = do_endian_conversion(event->event_size);
 119
 120        v += sizeof(struct tcpa_event) + converted_event_size;
 121
 122        /* now check if current entry is valid */
 123        if ((v + sizeof(struct tcpa_event)) > limit)
 124                return NULL;
 125
 126        event = v;
 127
 128        converted_event_size = do_endian_conversion(event->event_size);
 129        converted_event_type = do_endian_conversion(event->event_type);
 130
 131        if (((converted_event_type == 0) && (converted_event_size == 0)) ||
 132            ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
 133                return NULL;
 134
 135        (*pos)++;
 136        return v;
 137}
 138
 139static void tpm1_bios_measurements_stop(struct seq_file *m, void *v)
 140{
 141}
 142
 143static int get_event_name(char *dest, struct tcpa_event *event,
 144                        unsigned char * event_entry)
 145{
 146        const char *name = "";
 147        /* 41 so there is room for 40 data and 1 nul */
 148        char data[41] = "";
 149        int i, n_len = 0, d_len = 0;
 150        struct tcpa_pc_event *pc_event;
 151
 152        switch (do_endian_conversion(event->event_type)) {
 153        case PREBOOT:
 154        case POST_CODE:
 155        case UNUSED:
 156        case NO_ACTION:
 157        case SCRTM_CONTENTS:
 158        case SCRTM_VERSION:
 159        case CPU_MICROCODE:
 160        case PLATFORM_CONFIG_FLAGS:
 161        case TABLE_OF_DEVICES:
 162        case COMPACT_HASH:
 163        case IPL:
 164        case IPL_PARTITION_DATA:
 165        case NONHOST_CODE:
 166        case NONHOST_CONFIG:
 167        case NONHOST_INFO:
 168                name = tcpa_event_type_strings[do_endian_conversion
 169                                                (event->event_type)];
 170                n_len = strlen(name);
 171                break;
 172        case SEPARATOR:
 173        case ACTION:
 174                if (MAX_TEXT_EVENT >
 175                    do_endian_conversion(event->event_size)) {
 176                        name = event_entry;
 177                        n_len = do_endian_conversion(event->event_size);
 178                }
 179                break;
 180        case EVENT_TAG:
 181                pc_event = (struct tcpa_pc_event *)event_entry;
 182
 183                /* ToDo Row data -> Base64 */
 184
 185                switch (do_endian_conversion(pc_event->event_id)) {
 186                case SMBIOS:
 187                case BIS_CERT:
 188                case CMOS:
 189                case NVRAM:
 190                case OPTION_ROM_EXEC:
 191                case OPTION_ROM_CONFIG:
 192                case S_CRTM_VERSION:
 193                        name = tcpa_pc_event_id_strings[do_endian_conversion
 194                                                        (pc_event->event_id)];
 195                        n_len = strlen(name);
 196                        break;
 197                /* hash data */
 198                case POST_BIOS_ROM:
 199                case ESCD:
 200                case OPTION_ROM_MICROCODE:
 201                case S_CRTM_CONTENTS:
 202                case POST_CONTENTS:
 203                        name = tcpa_pc_event_id_strings[do_endian_conversion
 204                                                        (pc_event->event_id)];
 205                        n_len = strlen(name);
 206                        for (i = 0; i < 20; i++)
 207                                d_len += sprintf(&data[2*i], "%02x",
 208                                                pc_event->event_data[i]);
 209                        break;
 210                default:
 211                        break;
 212                }
 213        default:
 214                break;
 215        }
 216
 217        return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
 218                        n_len, name, d_len, data);
 219
 220}
 221
 222static int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
 223{
 224        struct tcpa_event *event = v;
 225        struct tcpa_event temp_event;
 226        char *temp_ptr;
 227        int i;
 228
 229        memcpy(&temp_event, event, sizeof(struct tcpa_event));
 230
 231        /* convert raw integers for endianness */
 232        temp_event.pcr_index = do_endian_conversion(event->pcr_index);
 233        temp_event.event_type = do_endian_conversion(event->event_type);
 234        temp_event.event_size = do_endian_conversion(event->event_size);
 235
 236        temp_ptr = (char *) &temp_event;
 237
 238        for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
 239                seq_putc(m, temp_ptr[i]);
 240
 241        temp_ptr = (char *) v;
 242
 243        for (i = (sizeof(struct tcpa_event) - 1);
 244             i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
 245                seq_putc(m, temp_ptr[i]);
 246
 247        return 0;
 248
 249}
 250
 251static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
 252{
 253        int len = 0;
 254        char *eventname;
 255        struct tcpa_event *event = v;
 256        unsigned char *event_entry =
 257            (unsigned char *)(v + sizeof(struct tcpa_event));
 258
 259        eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
 260        if (!eventname) {
 261                printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
 262                       __func__);
 263                return -EFAULT;
 264        }
 265
 266        /* 1st: PCR */
 267        seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
 268
 269        /* 2nd: SHA1 */
 270        seq_printf(m, "%20phN", event->pcr_value);
 271
 272        /* 3rd: event type identifier */
 273        seq_printf(m, " %02x", do_endian_conversion(event->event_type));
 274
 275        len += get_event_name(eventname, event, event_entry);
 276
 277        /* 4th: eventname <= max + \'0' delimiter */
 278        seq_printf(m, " %s\n", eventname);
 279
 280        kfree(eventname);
 281        return 0;
 282}
 283
 284const struct seq_operations tpm1_ascii_b_measurements_seqops = {
 285        .start = tpm1_bios_measurements_start,
 286        .next = tpm1_bios_measurements_next,
 287        .stop = tpm1_bios_measurements_stop,
 288        .show = tpm1_ascii_bios_measurements_show,
 289};
 290
 291const struct seq_operations tpm1_binary_b_measurements_seqops = {
 292        .start = tpm1_bios_measurements_start,
 293        .next = tpm1_bios_measurements_next,
 294        .stop = tpm1_bios_measurements_stop,
 295        .show = tpm1_binary_bios_measurements_show,
 296};
 297