linux/drivers/char/tpm/eventlog/tpm2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2016 IBM Corporation
   4 *
   5 * Authors:
   6 *      Nayna Jain <nayna@linux.vnet.ibm.com>
   7 *
   8 * Access to TPM 2.0 event log as written by Firmware.
   9 * It assumes that writer of event log has followed TCG Specification
  10 * for Family "2.0" and written the event data in little endian.
  11 * With that, it doesn't need any endian conversion for structure
  12 * content.
  13 */
  14
  15#include <linux/seq_file.h>
  16#include <linux/fs.h>
  17#include <linux/security.h>
  18#include <linux/module.h>
  19#include <linux/slab.h>
  20#include <linux/tpm_eventlog.h>
  21
  22#include "../tpm.h"
  23#include "common.h"
  24
  25/*
  26 * calc_tpm2_event_size() - calculate the event size, where event
  27 * is an entry in the TPM 2.0 event log. The event is of type Crypto
  28 * Agile Log Entry Format as defined in TCG EFI Protocol Specification
  29 * Family "2.0".
  30
  31 * @event: event whose size is to be calculated.
  32 * @event_header: the first event in the event log.
  33 *
  34 * Returns size of the event. If it is an invalid event, returns 0.
  35 */
  36static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
  37                                   struct tcg_pcr_event *event_header)
  38{
  39        return __calc_tpm2_event_size(event, event_header, false);
  40}
  41
  42static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
  43{
  44        struct tpm_chip *chip = m->private;
  45        struct tpm_bios_log *log = &chip->log;
  46        void *addr = log->bios_event_log;
  47        void *limit = log->bios_event_log_end;
  48        struct tcg_pcr_event *event_header;
  49        struct tcg_pcr_event2_head *event;
  50        size_t size;
  51        int i;
  52
  53        event_header = addr;
  54        size = struct_size(event_header, event, event_header->event_size);
  55
  56        if (*pos == 0) {
  57                if (addr + size < limit) {
  58                        if ((event_header->event_type == 0) &&
  59                            (event_header->event_size == 0))
  60                                return NULL;
  61                        return SEQ_START_TOKEN;
  62                }
  63        }
  64
  65        if (*pos > 0) {
  66                addr += size;
  67                event = addr;
  68                size = calc_tpm2_event_size(event, event_header);
  69                if ((addr + size >=  limit) || (size == 0))
  70                        return NULL;
  71        }
  72
  73        for (i = 0; i < (*pos - 1); i++) {
  74                event = addr;
  75                size = calc_tpm2_event_size(event, event_header);
  76
  77                if ((addr + size >= limit) || (size == 0))
  78                        return NULL;
  79                addr += size;
  80        }
  81
  82        return addr;
  83}
  84
  85static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
  86                                         loff_t *pos)
  87{
  88        struct tcg_pcr_event *event_header;
  89        struct tcg_pcr_event2_head *event;
  90        struct tpm_chip *chip = m->private;
  91        struct tpm_bios_log *log = &chip->log;
  92        void *limit = log->bios_event_log_end;
  93        size_t event_size;
  94        void *marker;
  95
  96        (*pos)++;
  97        event_header = log->bios_event_log;
  98
  99        if (v == SEQ_START_TOKEN) {
 100                event_size = struct_size(event_header, event,
 101                                         event_header->event_size);
 102                marker = event_header;
 103        } else {
 104                event = v;
 105                event_size = calc_tpm2_event_size(event, event_header);
 106                if (event_size == 0)
 107                        return NULL;
 108                marker = event;
 109        }
 110
 111        marker = marker + event_size;
 112        if (marker >= limit)
 113                return NULL;
 114        v = marker;
 115        event = v;
 116
 117        event_size = calc_tpm2_event_size(event, event_header);
 118        if (((v + event_size) >= limit) || (event_size == 0))
 119                return NULL;
 120
 121        return v;
 122}
 123
 124static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
 125{
 126}
 127
 128static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
 129{
 130        struct tpm_chip *chip = m->private;
 131        struct tpm_bios_log *log = &chip->log;
 132        struct tcg_pcr_event *event_header = log->bios_event_log;
 133        struct tcg_pcr_event2_head *event = v;
 134        void *temp_ptr;
 135        size_t size;
 136
 137        if (v == SEQ_START_TOKEN) {
 138                size = struct_size(event_header, event,
 139                                   event_header->event_size);
 140                temp_ptr = event_header;
 141
 142                if (size > 0)
 143                        seq_write(m, temp_ptr, size);
 144        } else {
 145                size = calc_tpm2_event_size(event, event_header);
 146                temp_ptr = event;
 147                if (size > 0)
 148                        seq_write(m, temp_ptr, size);
 149        }
 150
 151        return 0;
 152}
 153
 154const struct seq_operations tpm2_binary_b_measurements_seqops = {
 155        .start = tpm2_bios_measurements_start,
 156        .next = tpm2_bios_measurements_next,
 157        .stop = tpm2_bios_measurements_stop,
 158        .show = tpm2_binary_bios_measurements_show,
 159};
 160