18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 IBM Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Nayna Jain <nayna@linux.vnet.ibm.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Access to TPM 2.0 event log as written by Firmware. 98c2ecf20Sopenharmony_ci * It assumes that writer of event log has followed TCG Specification 108c2ecf20Sopenharmony_ci * for Family "2.0" and written the event data in little endian. 118c2ecf20Sopenharmony_ci * With that, it doesn't need any endian conversion for structure 128c2ecf20Sopenharmony_ci * content. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 168c2ecf20Sopenharmony_ci#include <linux/fs.h> 178c2ecf20Sopenharmony_ci#include <linux/security.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/tpm_eventlog.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "../tpm.h" 238c2ecf20Sopenharmony_ci#include "common.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * calc_tpm2_event_size() - calculate the event size, where event 278c2ecf20Sopenharmony_ci * is an entry in the TPM 2.0 event log. The event is of type Crypto 288c2ecf20Sopenharmony_ci * Agile Log Entry Format as defined in TCG EFI Protocol Specification 298c2ecf20Sopenharmony_ci * Family "2.0". 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci * @event: event whose size is to be calculated. 328c2ecf20Sopenharmony_ci * @event_header: the first event in the event log. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Returns size of the event. If it is an invalid event, returns 0. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistatic size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, 378c2ecf20Sopenharmony_ci struct tcg_pcr_event *event_header) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return __calc_tpm2_event_size(event, event_header, false); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct tpm_chip *chip = m->private; 458c2ecf20Sopenharmony_ci struct tpm_bios_log *log = &chip->log; 468c2ecf20Sopenharmony_ci void *addr = log->bios_event_log; 478c2ecf20Sopenharmony_ci void *limit = log->bios_event_log_end; 488c2ecf20Sopenharmony_ci struct tcg_pcr_event *event_header; 498c2ecf20Sopenharmony_ci struct tcg_pcr_event2_head *event; 508c2ecf20Sopenharmony_ci size_t size; 518c2ecf20Sopenharmony_ci int i; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci event_header = addr; 548c2ecf20Sopenharmony_ci size = struct_size(event_header, event, event_header->event_size); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (*pos == 0) { 578c2ecf20Sopenharmony_ci if (addr + size < limit) { 588c2ecf20Sopenharmony_ci if ((event_header->event_type == 0) && 598c2ecf20Sopenharmony_ci (event_header->event_size == 0)) 608c2ecf20Sopenharmony_ci return NULL; 618c2ecf20Sopenharmony_ci return SEQ_START_TOKEN; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (*pos > 0) { 668c2ecf20Sopenharmony_ci addr += size; 678c2ecf20Sopenharmony_ci event = addr; 688c2ecf20Sopenharmony_ci size = calc_tpm2_event_size(event, event_header); 698c2ecf20Sopenharmony_ci if ((addr + size >= limit) || (size == 0)) 708c2ecf20Sopenharmony_ci return NULL; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci for (i = 0; i < (*pos - 1); i++) { 748c2ecf20Sopenharmony_ci event = addr; 758c2ecf20Sopenharmony_ci size = calc_tpm2_event_size(event, event_header); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if ((addr + size >= limit) || (size == 0)) 788c2ecf20Sopenharmony_ci return NULL; 798c2ecf20Sopenharmony_ci addr += size; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return addr; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void *tpm2_bios_measurements_next(struct seq_file *m, void *v, 868c2ecf20Sopenharmony_ci loff_t *pos) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct tcg_pcr_event *event_header; 898c2ecf20Sopenharmony_ci struct tcg_pcr_event2_head *event; 908c2ecf20Sopenharmony_ci struct tpm_chip *chip = m->private; 918c2ecf20Sopenharmony_ci struct tpm_bios_log *log = &chip->log; 928c2ecf20Sopenharmony_ci void *limit = log->bios_event_log_end; 938c2ecf20Sopenharmony_ci size_t event_size; 948c2ecf20Sopenharmony_ci void *marker; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci (*pos)++; 978c2ecf20Sopenharmony_ci event_header = log->bios_event_log; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) { 1008c2ecf20Sopenharmony_ci event_size = struct_size(event_header, event, 1018c2ecf20Sopenharmony_ci event_header->event_size); 1028c2ecf20Sopenharmony_ci marker = event_header; 1038c2ecf20Sopenharmony_ci } else { 1048c2ecf20Sopenharmony_ci event = v; 1058c2ecf20Sopenharmony_ci event_size = calc_tpm2_event_size(event, event_header); 1068c2ecf20Sopenharmony_ci if (event_size == 0) 1078c2ecf20Sopenharmony_ci return NULL; 1088c2ecf20Sopenharmony_ci marker = event; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci marker = marker + event_size; 1128c2ecf20Sopenharmony_ci if (marker >= limit) 1138c2ecf20Sopenharmony_ci return NULL; 1148c2ecf20Sopenharmony_ci v = marker; 1158c2ecf20Sopenharmony_ci event = v; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci event_size = calc_tpm2_event_size(event, event_header); 1188c2ecf20Sopenharmony_ci if (((v + event_size) >= limit) || (event_size == 0)) 1198c2ecf20Sopenharmony_ci return NULL; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return v; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void tpm2_bios_measurements_stop(struct seq_file *m, void *v) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct tpm_chip *chip = m->private; 1318c2ecf20Sopenharmony_ci struct tpm_bios_log *log = &chip->log; 1328c2ecf20Sopenharmony_ci struct tcg_pcr_event *event_header = log->bios_event_log; 1338c2ecf20Sopenharmony_ci struct tcg_pcr_event2_head *event = v; 1348c2ecf20Sopenharmony_ci void *temp_ptr; 1358c2ecf20Sopenharmony_ci size_t size; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) { 1388c2ecf20Sopenharmony_ci size = struct_size(event_header, event, 1398c2ecf20Sopenharmony_ci event_header->event_size); 1408c2ecf20Sopenharmony_ci temp_ptr = event_header; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (size > 0) 1438c2ecf20Sopenharmony_ci seq_write(m, temp_ptr, size); 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci size = calc_tpm2_event_size(event, event_header); 1468c2ecf20Sopenharmony_ci temp_ptr = event; 1478c2ecf20Sopenharmony_ci if (size > 0) 1488c2ecf20Sopenharmony_ci seq_write(m, temp_ptr, size); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciconst struct seq_operations tpm2_binary_b_measurements_seqops = { 1558c2ecf20Sopenharmony_ci .start = tpm2_bios_measurements_start, 1568c2ecf20Sopenharmony_ci .next = tpm2_bios_measurements_next, 1578c2ecf20Sopenharmony_ci .stop = tpm2_bios_measurements_stop, 1588c2ecf20Sopenharmony_ci .show = tpm2_binary_bios_measurements_show, 1598c2ecf20Sopenharmony_ci}; 160