162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 IBM Corporation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Nayna Jain <nayna@linux.vnet.ibm.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Access to TPM 2.0 event log as written by Firmware. 962306a36Sopenharmony_ci * It assumes that writer of event log has followed TCG Specification 1062306a36Sopenharmony_ci * for Family "2.0" and written the event data in little endian. 1162306a36Sopenharmony_ci * With that, it doesn't need any endian conversion for structure 1262306a36Sopenharmony_ci * content. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/seq_file.h> 1662306a36Sopenharmony_ci#include <linux/fs.h> 1762306a36Sopenharmony_ci#include <linux/security.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/tpm_eventlog.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "../tpm.h" 2362306a36Sopenharmony_ci#include "common.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * calc_tpm2_event_size() - calculate the event size, where event 2762306a36Sopenharmony_ci * is an entry in the TPM 2.0 event log. The event is of type Crypto 2862306a36Sopenharmony_ci * Agile Log Entry Format as defined in TCG EFI Protocol Specification 2962306a36Sopenharmony_ci * Family "2.0". 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci * @event: event whose size is to be calculated. 3262306a36Sopenharmony_ci * @event_header: the first event in the event log. 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Returns size of the event. If it is an invalid event, returns 0. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, 3762306a36Sopenharmony_ci struct tcg_pcr_event *event_header) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci return __calc_tpm2_event_size(event, event_header, false); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct tpm_chip *chip = m->private; 4562306a36Sopenharmony_ci struct tpm_bios_log *log = &chip->log; 4662306a36Sopenharmony_ci void *addr = log->bios_event_log; 4762306a36Sopenharmony_ci void *limit = log->bios_event_log_end; 4862306a36Sopenharmony_ci struct tcg_pcr_event *event_header; 4962306a36Sopenharmony_ci struct tcg_pcr_event2_head *event; 5062306a36Sopenharmony_ci size_t size; 5162306a36Sopenharmony_ci int i; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci event_header = addr; 5462306a36Sopenharmony_ci size = struct_size(event_header, event, event_header->event_size); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (*pos == 0) { 5762306a36Sopenharmony_ci if (addr + size < limit) { 5862306a36Sopenharmony_ci if ((event_header->event_type == 0) && 5962306a36Sopenharmony_ci (event_header->event_size == 0)) 6062306a36Sopenharmony_ci return NULL; 6162306a36Sopenharmony_ci return SEQ_START_TOKEN; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (*pos > 0) { 6662306a36Sopenharmony_ci addr += size; 6762306a36Sopenharmony_ci event = addr; 6862306a36Sopenharmony_ci size = calc_tpm2_event_size(event, event_header); 6962306a36Sopenharmony_ci if ((addr + size >= limit) || (size == 0)) 7062306a36Sopenharmony_ci return NULL; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci for (i = 0; i < (*pos - 1); i++) { 7462306a36Sopenharmony_ci event = addr; 7562306a36Sopenharmony_ci size = calc_tpm2_event_size(event, event_header); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if ((addr + size >= limit) || (size == 0)) 7862306a36Sopenharmony_ci return NULL; 7962306a36Sopenharmony_ci addr += size; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return addr; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void *tpm2_bios_measurements_next(struct seq_file *m, void *v, 8662306a36Sopenharmony_ci loff_t *pos) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct tcg_pcr_event *event_header; 8962306a36Sopenharmony_ci struct tcg_pcr_event2_head *event; 9062306a36Sopenharmony_ci struct tpm_chip *chip = m->private; 9162306a36Sopenharmony_ci struct tpm_bios_log *log = &chip->log; 9262306a36Sopenharmony_ci void *limit = log->bios_event_log_end; 9362306a36Sopenharmony_ci size_t event_size; 9462306a36Sopenharmony_ci void *marker; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci (*pos)++; 9762306a36Sopenharmony_ci event_header = log->bios_event_log; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 10062306a36Sopenharmony_ci event_size = struct_size(event_header, event, 10162306a36Sopenharmony_ci event_header->event_size); 10262306a36Sopenharmony_ci marker = event_header; 10362306a36Sopenharmony_ci } else { 10462306a36Sopenharmony_ci event = v; 10562306a36Sopenharmony_ci event_size = calc_tpm2_event_size(event, event_header); 10662306a36Sopenharmony_ci if (event_size == 0) 10762306a36Sopenharmony_ci return NULL; 10862306a36Sopenharmony_ci marker = event; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci marker = marker + event_size; 11262306a36Sopenharmony_ci if (marker >= limit) 11362306a36Sopenharmony_ci return NULL; 11462306a36Sopenharmony_ci v = marker; 11562306a36Sopenharmony_ci event = v; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci event_size = calc_tpm2_event_size(event, event_header); 11862306a36Sopenharmony_ci if (((v + event_size) >= limit) || (event_size == 0)) 11962306a36Sopenharmony_ci return NULL; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return v; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void tpm2_bios_measurements_stop(struct seq_file *m, void *v) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct tpm_chip *chip = m->private; 13162306a36Sopenharmony_ci struct tpm_bios_log *log = &chip->log; 13262306a36Sopenharmony_ci struct tcg_pcr_event *event_header = log->bios_event_log; 13362306a36Sopenharmony_ci struct tcg_pcr_event2_head *event = v; 13462306a36Sopenharmony_ci void *temp_ptr; 13562306a36Sopenharmony_ci size_t size; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 13862306a36Sopenharmony_ci size = struct_size(event_header, event, 13962306a36Sopenharmony_ci event_header->event_size); 14062306a36Sopenharmony_ci temp_ptr = event_header; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (size > 0) 14362306a36Sopenharmony_ci seq_write(m, temp_ptr, size); 14462306a36Sopenharmony_ci } else { 14562306a36Sopenharmony_ci size = calc_tpm2_event_size(event, event_header); 14662306a36Sopenharmony_ci temp_ptr = event; 14762306a36Sopenharmony_ci if (size > 0) 14862306a36Sopenharmony_ci seq_write(m, temp_ptr, size); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciconst struct seq_operations tpm2_binary_b_measurements_seqops = { 15562306a36Sopenharmony_ci .start = tpm2_bios_measurements_start, 15662306a36Sopenharmony_ci .next = tpm2_bios_measurements_next, 15762306a36Sopenharmony_ci .stop = tpm2_bios_measurements_stop, 15862306a36Sopenharmony_ci .show = tpm2_binary_bios_measurements_show, 15962306a36Sopenharmony_ci}; 160