diff options
Diffstat (limited to 'drivers/char/tpm/eventlog/tpm2.c')
-rw-r--r-- | drivers/char/tpm/eventlog/tpm2.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c new file mode 100644 index 000000000..37a058009 --- /dev/null +++ b/drivers/char/tpm/eventlog/tpm2.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2016 IBM Corporation + * + * Authors: + * Nayna Jain <nayna@linux.vnet.ibm.com> + * + * Access to TPM 2.0 event log as written by Firmware. + * It assumes that writer of event log has followed TCG Specification + * for Family "2.0" and written the event data in little endian. + * With that, it doesn't need any endian conversion for structure + * content. + */ + +#include <linux/seq_file.h> +#include <linux/fs.h> +#include <linux/security.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/tpm_eventlog.h> + +#include "../tpm.h" +#include "common.h" + +/* + * calc_tpm2_event_size() - calculate the event size, where event + * is an entry in the TPM 2.0 event log. The event is of type Crypto + * Agile Log Entry Format as defined in TCG EFI Protocol Specification + * Family "2.0". + + * @event: event whose size is to be calculated. + * @event_header: the first event in the event log. + * + * Returns size of the event. If it is an invalid event, returns 0. + */ +static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, + struct tcg_pcr_event *event_header) +{ + return __calc_tpm2_event_size(event, event_header, false); +} + +static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) +{ + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *addr = log->bios_event_log; + void *limit = log->bios_event_log_end; + struct tcg_pcr_event *event_header; + struct tcg_pcr_event2_head *event; + size_t size; + int i; + + event_header = addr; + size = struct_size(event_header, event, event_header->event_size); + + if (*pos == 0) { + if (addr + size < limit) { + if ((event_header->event_type == 0) && + (event_header->event_size == 0)) + return NULL; + return SEQ_START_TOKEN; + } + } + + if (*pos > 0) { + addr += size; + event = addr; + size = calc_tpm2_event_size(event, event_header); + if ((addr + size >= limit) || (size == 0)) + return NULL; + } + + for (i = 0; i < (*pos - 1); i++) { + event = addr; + size = calc_tpm2_event_size(event, event_header); + + if ((addr + size >= limit) || (size == 0)) + return NULL; + addr += size; + } + + return addr; +} + +static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, + loff_t *pos) +{ + struct tcg_pcr_event *event_header; + struct tcg_pcr_event2_head *event; + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + void *limit = log->bios_event_log_end; + size_t event_size; + void *marker; + + (*pos)++; + event_header = log->bios_event_log; + + if (v == SEQ_START_TOKEN) { + event_size = struct_size(event_header, event, + event_header->event_size); + marker = event_header; + } else { + event = v; + event_size = calc_tpm2_event_size(event, event_header); + if (event_size == 0) + return NULL; + marker = event; + } + + marker = marker + event_size; + if (marker >= limit) + return NULL; + v = marker; + event = v; + + event_size = calc_tpm2_event_size(event, event_header); + if (((v + event_size) >= limit) || (event_size == 0)) + return NULL; + + return v; +} + +static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) +{ +} + +static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) +{ + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; + struct tcg_pcr_event *event_header = log->bios_event_log; + struct tcg_pcr_event2_head *event = v; + void *temp_ptr; + size_t size; + + if (v == SEQ_START_TOKEN) { + size = struct_size(event_header, event, + event_header->event_size); + temp_ptr = event_header; + + if (size > 0) + seq_write(m, temp_ptr, size); + } else { + size = calc_tpm2_event_size(event, event_header); + temp_ptr = event; + if (size > 0) + seq_write(m, temp_ptr, size); + } + + return 0; +} + +const struct seq_operations tpm2_binary_b_measurements_seqops = { + .start = tpm2_bios_measurements_start, + .next = tpm2_bios_measurements_next, + .stop = tpm2_bios_measurements_stop, + .show = tpm2_binary_bios_measurements_show, +}; |