linux/drivers/char/tpm/tpm_eventlog.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005, 2012 IBM Corporation
   3 *
   4 * Authors:
   5 *      Kent Yoder <key@linux.vnet.ibm.com>
   6 *      Seiji Munetoh <munetoh@jp.ibm.com>
   7 *      Stefan Berger <stefanb@us.ibm.com>
   8 *      Reiner Sailer <sailer@watson.ibm.com>
   9 *      Kylene Hall <kjhall@us.ibm.com>
  10 *
  11 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  12 *
  13 * Access to the eventlog created by a system's firmware / BIOS
  14 *
  15 * This program is free software; you can redistribute it and/or
  16 * modify it under the terms of the GNU General Public License
  17 * as published by the Free Software Foundation; either version
  18 * 2 of the License, or (at your option) any later version.
  19 *
  20 */
  21
  22#include <linux/seq_file.h>
  23#include <linux/fs.h>
  24#include <linux/security.h>
  25#include <linux/module.h>
  26#include <linux/slab.h>
  27
  28#include "tpm.h"
  29#include "tpm_eventlog.h"
  30
  31
  32static const char* tcpa_event_type_strings[] = {
  33        "PREBOOT",
  34        "POST CODE",
  35        "",
  36        "NO ACTION",
  37        "SEPARATOR",
  38        "ACTION",
  39        "EVENT TAG",
  40        "S-CRTM Contents",
  41        "S-CRTM Version",
  42        "CPU Microcode",
  43        "Platform Config Flags",
  44        "Table of Devices",
  45        "Compact Hash",
  46        "IPL",
  47        "IPL Partition Data",
  48        "Non-Host Code",
  49        "Non-Host Config",
  50        "Non-Host Info"
  51};
  52
  53static const char* tcpa_pc_event_id_strings[] = {
  54        "",
  55        "SMBIOS",
  56        "BIS Certificate",
  57        "POST BIOS ",
  58        "ESCD ",
  59        "CMOS",
  60        "NVRAM",
  61        "Option ROM",
  62        "Option ROM config",
  63        "",
  64        "Option ROM microcode ",
  65        "S-CRTM Version",
  66        "S-CRTM Contents ",
  67        "POST Contents ",
  68        "Table of Devices",
  69};
  70
  71/* returns pointer to start of pos. entry of tcg log */
  72static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
  73{
  74        loff_t i;
  75        struct tpm_bios_log *log = m->private;
  76        void *addr = log->bios_event_log;
  77        void *limit = log->bios_event_log_end;
  78        struct tcpa_event *event;
  79        u32 converted_event_size;
  80        u32 converted_event_type;
  81
  82
  83        /* read over *pos measurements */
  84        for (i = 0; i < *pos; i++) {
  85                event = addr;
  86
  87                converted_event_size =
  88                    do_endian_conversion(event->event_size);
  89                converted_event_type =
  90                    do_endian_conversion(event->event_type);
  91
  92                if ((addr + sizeof(struct tcpa_event)) < limit) {
  93                        if ((converted_event_type == 0) &&
  94                            (converted_event_size == 0))
  95                                return NULL;
  96                        addr += (sizeof(struct tcpa_event) +
  97                                 converted_event_size);
  98                }
  99        }
 100
 101        /* now check if current entry is valid */
 102        if ((addr + sizeof(struct tcpa_event)) >= limit)
 103                return NULL;
 104
 105        event = addr;
 106
 107        converted_event_size = do_endian_conversion(event->event_size);
 108        converted_event_type = do_endian_conversion(event->event_type);
 109
 110        if (((converted_event_type == 0) && (converted_event_size == 0))
 111            || ((addr + sizeof(struct tcpa_event) + converted_event_size)
 112                >= limit))
 113                return NULL;
 114
 115        return addr;
 116}
 117
 118static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
 119                                        loff_t *pos)
 120{
 121        struct tcpa_event *event = v;
 122        struct tpm_bios_log *log = m->private;
 123        void *limit = log->bios_event_log_end;
 124        u32 converted_event_size;
 125        u32 converted_event_type;
 126
 127        converted_event_size = do_endian_conversion(event->event_size);
 128
 129        v += sizeof(struct tcpa_event) + converted_event_size;
 130
 131        /* now check if current entry is valid */
 132        if ((v + sizeof(struct tcpa_event)) >= limit)
 133                return NULL;
 134
 135        event = v;
 136
 137        converted_event_size = do_endian_conversion(event->event_size);
 138        converted_event_type = do_endian_conversion(event->event_type);
 139
 140        if (((converted_event_type == 0) && (converted_event_size == 0)) ||
 141            ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
 142                return NULL;
 143
 144        (*pos)++;
 145        return v;
 146}
 147
 148static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
 149{
 150}
 151
 152static int get_event_name(char *dest, struct tcpa_event *event,
 153                        unsigned char * event_entry)
 154{
 155        const char *name = "";
 156        /* 41 so there is room for 40 data and 1 nul */
 157        char data[41] = "";
 158        int i, n_len = 0, d_len = 0;
 159        struct tcpa_pc_event *pc_event;
 160
 161        switch (do_endian_conversion(event->event_type)) {
 162        case PREBOOT:
 163        case POST_CODE:
 164        case UNUSED:
 165        case NO_ACTION:
 166        case SCRTM_CONTENTS:
 167        case SCRTM_VERSION:
 168        case CPU_MICROCODE:
 169        case PLATFORM_CONFIG_FLAGS:
 170        case TABLE_OF_DEVICES:
 171        case COMPACT_HASH:
 172        case IPL:
 173        case IPL_PARTITION_DATA:
 174        case NONHOST_CODE:
 175        case NONHOST_CONFIG:
 176        case NONHOST_INFO:
 177                name = tcpa_event_type_strings[do_endian_conversion
 178                                                (event->event_type)];
 179                n_len = strlen(name);
 180                break;
 181        case SEPARATOR:
 182        case ACTION:
 183                if (MAX_TEXT_EVENT >
 184                    do_endian_conversion(event->event_size)) {
 185                        name = event_entry;
 186                        n_len = do_endian_conversion(event->event_size);
 187                }
 188                break;
 189        case EVENT_TAG:
 190                pc_event = (struct tcpa_pc_event *)event_entry;
 191
 192                /* ToDo Row data -> Base64 */
 193
 194                switch (do_endian_conversion(pc_event->event_id)) {
 195                case SMBIOS:
 196                case BIS_CERT:
 197                case CMOS:
 198                case NVRAM:
 199                case OPTION_ROM_EXEC:
 200                case OPTION_ROM_CONFIG:
 201                case S_CRTM_VERSION:
 202                        name = tcpa_pc_event_id_strings[do_endian_conversion
 203                                                        (pc_event->event_id)];
 204                        n_len = strlen(name);
 205                        break;
 206                /* hash data */
 207                case POST_BIOS_ROM:
 208                case ESCD:
 209                case OPTION_ROM_MICROCODE:
 210                case S_CRTM_CONTENTS:
 211                case POST_CONTENTS:
 212                        name = tcpa_pc_event_id_strings[do_endian_conversion
 213                                                        (pc_event->event_id)];
 214                        n_len = strlen(name);
 215                        for (i = 0; i < 20; i++)
 216                                d_len += sprintf(&data[2*i], "%02x",
 217                                                pc_event->event_data[i]);
 218                        break;
 219                default:
 220                        break;
 221                }
 222        default:
 223                break;
 224        }
 225
 226        return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
 227                        n_len, name, d_len, data);
 228
 229}
 230
 231static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
 232{
 233        struct tcpa_event *event = v;
 234        struct tcpa_event temp_event;
 235        char *temp_ptr;
 236        int i;
 237
 238        memcpy(&temp_event, event, sizeof(struct tcpa_event));
 239
 240        /* convert raw integers for endianness */
 241        temp_event.pcr_index = do_endian_conversion(event->pcr_index);
 242        temp_event.event_type = do_endian_conversion(event->event_type);
 243        temp_event.event_size = do_endian_conversion(event->event_size);
 244
 245        temp_ptr = (char *) &temp_event;
 246
 247        for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
 248                seq_putc(m, temp_ptr[i]);
 249
 250        temp_ptr = (char *) v;
 251
 252        for (i = (sizeof(struct tcpa_event) - 1);
 253             i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
 254                seq_putc(m, temp_ptr[i]);
 255
 256        return 0;
 257
 258}
 259
 260static int tpm_bios_measurements_release(struct inode *inode,
 261                                         struct file *file)
 262{
 263        struct seq_file *seq = file->private_data;
 264        struct tpm_bios_log *log = seq->private;
 265
 266        if (log) {
 267                kfree(log->bios_event_log);
 268                kfree(log);
 269        }
 270
 271        return seq_release(inode, file);
 272}
 273
 274static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
 275{
 276        int len = 0;
 277        char *eventname;
 278        struct tcpa_event *event = v;
 279        unsigned char *event_entry =
 280            (unsigned char *)(v + sizeof(struct tcpa_event));
 281
 282        eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
 283        if (!eventname) {
 284                printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
 285                       __func__);
 286                return -EFAULT;
 287        }
 288
 289        /* 1st: PCR */
 290        seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
 291
 292        /* 2nd: SHA1 */
 293        seq_printf(m, "%20phN", event->pcr_value);
 294
 295        /* 3rd: event type identifier */
 296        seq_printf(m, " %02x", do_endian_conversion(event->event_type));
 297
 298        len += get_event_name(eventname, event, event_entry);
 299
 300        /* 4th: eventname <= max + \'0' delimiter */
 301        seq_printf(m, " %s\n", eventname);
 302
 303        kfree(eventname);
 304        return 0;
 305}
 306
 307static const struct seq_operations tpm_ascii_b_measurments_seqops = {
 308        .start = tpm_bios_measurements_start,
 309        .next = tpm_bios_measurements_next,
 310        .stop = tpm_bios_measurements_stop,
 311        .show = tpm_ascii_bios_measurements_show,
 312};
 313
 314static const struct seq_operations tpm_binary_b_measurments_seqops = {
 315        .start = tpm_bios_measurements_start,
 316        .next = tpm_bios_measurements_next,
 317        .stop = tpm_bios_measurements_stop,
 318        .show = tpm_binary_bios_measurements_show,
 319};
 320
 321static int tpm_ascii_bios_measurements_open(struct inode *inode,
 322                                            struct file *file)
 323{
 324        int err;
 325        struct tpm_bios_log *log;
 326        struct seq_file *seq;
 327
 328        log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
 329        if (!log)
 330                return -ENOMEM;
 331
 332        if ((err = read_log(log)))
 333                goto out_free;
 334
 335        /* now register seq file */
 336        err = seq_open(file, &tpm_ascii_b_measurments_seqops);
 337        if (!err) {
 338                seq = file->private_data;
 339                seq->private = log;
 340        } else {
 341                goto out_free;
 342        }
 343
 344out:
 345        return err;
 346out_free:
 347        kfree(log->bios_event_log);
 348        kfree(log);
 349        goto out;
 350}
 351
 352static const struct file_operations tpm_ascii_bios_measurements_ops = {
 353        .open = tpm_ascii_bios_measurements_open,
 354        .read = seq_read,
 355        .llseek = seq_lseek,
 356        .release = tpm_bios_measurements_release,
 357};
 358
 359static int tpm_binary_bios_measurements_open(struct inode *inode,
 360                                             struct file *file)
 361{
 362        int err;
 363        struct tpm_bios_log *log;
 364        struct seq_file *seq;
 365
 366        log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
 367        if (!log)
 368                return -ENOMEM;
 369
 370        if ((err = read_log(log)))
 371                goto out_free;
 372
 373        /* now register seq file */
 374        err = seq_open(file, &tpm_binary_b_measurments_seqops);
 375        if (!err) {
 376                seq = file->private_data;
 377                seq->private = log;
 378        } else {
 379                goto out_free;
 380        }
 381
 382out:
 383        return err;
 384out_free:
 385        kfree(log->bios_event_log);
 386        kfree(log);
 387        goto out;
 388}
 389
 390static const struct file_operations tpm_binary_bios_measurements_ops = {
 391        .open = tpm_binary_bios_measurements_open,
 392        .read = seq_read,
 393        .llseek = seq_lseek,
 394        .release = tpm_bios_measurements_release,
 395};
 396
 397static int is_bad(void *p)
 398{
 399        if (!p)
 400                return 1;
 401        if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV))
 402                return 1;
 403        return 0;
 404}
 405
 406struct dentry **tpm_bios_log_setup(char *name)
 407{
 408        struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
 409
 410        tpm_dir = securityfs_create_dir(name, NULL);
 411        if (is_bad(tpm_dir))
 412                goto out;
 413
 414        bin_file =
 415            securityfs_create_file("binary_bios_measurements",
 416                                   S_IRUSR | S_IRGRP, tpm_dir, NULL,
 417                                   &tpm_binary_bios_measurements_ops);
 418        if (is_bad(bin_file))
 419                goto out_tpm;
 420
 421        ascii_file =
 422            securityfs_create_file("ascii_bios_measurements",
 423                                   S_IRUSR | S_IRGRP, tpm_dir, NULL,
 424                                   &tpm_ascii_bios_measurements_ops);
 425        if (is_bad(ascii_file))
 426                goto out_bin;
 427
 428        ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
 429        if (!ret)
 430                goto out_ascii;
 431
 432        ret[0] = ascii_file;
 433        ret[1] = bin_file;
 434        ret[2] = tpm_dir;
 435
 436        return ret;
 437
 438out_ascii:
 439        securityfs_remove(ascii_file);
 440out_bin:
 441        securityfs_remove(bin_file);
 442out_tpm:
 443        securityfs_remove(tpm_dir);
 444out:
 445        return NULL;
 446}
 447
 448void tpm_bios_log_teardown(struct dentry **lst)
 449{
 450        int i;
 451
 452        for (i = 0; i < 3; i++)
 453                securityfs_remove(lst[i]);
 454}
 455