linux/drivers/char/tpm/eventlog/tpm2.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 IBM Corporation
   3 *
   4 * Authors:
   5 *      Nayna Jain <nayna@linux.vnet.ibm.com>
   6 *
   7 * Access to TPM 2.0 event log as written by Firmware.
   8 * It assumes that writer of event log has followed TCG Specification
   9 * for Family "2.0" and written the event data in little endian.
  10 * With that, it doesn't need any endian conversion for structure
  11 * content.
  12 *
  13 * This program is free software; you can redistribute it and/or
  14 * modify it under the terms of the GNU General Public License
  15 * as published by the Free Software Foundation; either version
  16 * 2 of the License, or (at your option) any later version.
  17 */
  18
  19#include <linux/seq_file.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/*
  30 * calc_tpm2_event_size() - calculate the event size, where event
  31 * is an entry in the TPM 2.0 event log. The event is of type Crypto
  32 * Agile Log Entry Format as defined in TCG EFI Protocol Specification
  33 * Family "2.0".
  34
  35 * @event: event whose size is to be calculated.
  36 * @event_header: the first event in the event log.
  37 *
  38 * Returns size of the event. If it is an invalid event, returns 0.
  39 */
  40static int calc_tpm2_event_size(struct tcg_pcr_event2 *event,
  41                                struct tcg_pcr_event *event_header)
  42{
  43        struct tcg_efi_specid_event *efispecid;
  44        struct tcg_event_field *event_field;
  45        void *marker;
  46        void *marker_start;
  47        u32 halg_size;
  48        size_t size;
  49        u16 halg;
  50        int i;
  51        int j;
  52
  53        marker = event;
  54        marker_start = marker;
  55        marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
  56                + sizeof(event->count);
  57
  58        efispecid = (struct tcg_efi_specid_event *)event_header->event;
  59
  60        /* Check if event is malformed. */
  61        if (event->count > efispecid->num_algs)
  62                return 0;
  63
  64        for (i = 0; i < event->count; i++) {
  65                halg_size = sizeof(event->digests[i].alg_id);
  66                memcpy(&halg, marker, halg_size);
  67                marker = marker + halg_size;
  68                for (j = 0; j < efispecid->num_algs; j++) {
  69                        if (halg == efispecid->digest_sizes[j].alg_id) {
  70                                marker +=
  71                                        efispecid->digest_sizes[j].digest_size;
  72                                break;
  73                        }
  74                }
  75                /* Algorithm without known length. Such event is unparseable. */
  76                if (j == efispecid->num_algs)
  77                        return 0;
  78        }
  79
  80        event_field = (struct tcg_event_field *)marker;
  81        marker = marker + sizeof(event_field->event_size)
  82                + event_field->event_size;
  83        size = marker - marker_start;
  84
  85        if ((event->event_type == 0) && (event_field->event_size == 0))
  86                return 0;
  87
  88        return size;
  89}
  90
  91static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
  92{
  93        struct tpm_chip *chip = m->private;
  94        struct tpm_bios_log *log = &chip->log;
  95        void *addr = log->bios_event_log;
  96        void *limit = log->bios_event_log_end;
  97        struct tcg_pcr_event *event_header;
  98        struct tcg_pcr_event2 *event;
  99        size_t size;
 100        int i;
 101
 102        event_header = addr;
 103        size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event)
 104                + event_header->event_size;
 105
 106        if (*pos == 0) {
 107                if (addr + size < limit) {
 108                        if ((event_header->event_type == 0) &&
 109                            (event_header->event_size == 0))
 110                                return NULL;
 111                        return SEQ_START_TOKEN;
 112                }
 113        }
 114
 115        if (*pos > 0) {
 116                addr += size;
 117                event = addr;
 118                size = calc_tpm2_event_size(event, event_header);
 119                if ((addr + size >=  limit) || (size == 0))
 120                        return NULL;
 121        }
 122
 123        for (i = 0; i < (*pos - 1); i++) {
 124                event = addr;
 125                size = calc_tpm2_event_size(event, event_header);
 126
 127                if ((addr + size >= limit) || (size == 0))
 128                        return NULL;
 129                addr += size;
 130        }
 131
 132        return addr;
 133}
 134
 135static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
 136                                         loff_t *pos)
 137{
 138        struct tcg_pcr_event *event_header;
 139        struct tcg_pcr_event2 *event;
 140        struct tpm_chip *chip = m->private;
 141        struct tpm_bios_log *log = &chip->log;
 142        void *limit = log->bios_event_log_end;
 143        size_t event_size;
 144        void *marker;
 145
 146        event_header = log->bios_event_log;
 147
 148        if (v == SEQ_START_TOKEN) {
 149                event_size = sizeof(struct tcg_pcr_event) -
 150                        sizeof(event_header->event) + event_header->event_size;
 151                marker = event_header;
 152        } else {
 153                event = v;
 154                event_size = calc_tpm2_event_size(event, event_header);
 155                if (event_size == 0)
 156                        return NULL;
 157                marker = event;
 158        }
 159
 160        marker = marker + event_size;
 161        if (marker >= limit)
 162                return NULL;
 163        v = marker;
 164        event = v;
 165
 166        event_size = calc_tpm2_event_size(event, event_header);
 167        if (((v + event_size) >= limit) || (event_size == 0))
 168                return NULL;
 169
 170        (*pos)++;
 171        return v;
 172}
 173
 174static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
 175{
 176}
 177
 178static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
 179{
 180        struct tpm_chip *chip = m->private;
 181        struct tpm_bios_log *log = &chip->log;
 182        struct tcg_pcr_event *event_header = log->bios_event_log;
 183        struct tcg_pcr_event2 *event = v;
 184        void *temp_ptr;
 185        size_t size;
 186
 187        if (v == SEQ_START_TOKEN) {
 188                size = sizeof(struct tcg_pcr_event) -
 189                        sizeof(event_header->event) + event_header->event_size;
 190
 191                temp_ptr = event_header;
 192
 193                if (size > 0)
 194                        seq_write(m, temp_ptr, size);
 195        } else {
 196                size = calc_tpm2_event_size(event, event_header);
 197                temp_ptr = event;
 198                if (size > 0)
 199                        seq_write(m, temp_ptr, size);
 200        }
 201
 202        return 0;
 203}
 204
 205const struct seq_operations tpm2_binary_b_measurements_seqops = {
 206        .start = tpm2_bios_measurements_start,
 207        .next = tpm2_bios_measurements_next,
 208        .stop = tpm2_bios_measurements_stop,
 209        .show = tpm2_binary_bios_measurements_show,
 210};
 211