18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2005, 2012 IBM Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Kent Yoder <key@linux.vnet.ibm.com> 78c2ecf20Sopenharmony_ci * Seiji Munetoh <munetoh@jp.ibm.com> 88c2ecf20Sopenharmony_ci * Stefan Berger <stefanb@us.ibm.com> 98c2ecf20Sopenharmony_ci * Reiner Sailer <sailer@watson.ibm.com> 108c2ecf20Sopenharmony_ci * Kylene Hall <kjhall@us.ibm.com> 118c2ecf20Sopenharmony_ci * Nayna Jain <nayna@linux.vnet.ibm.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Access to the event log created by a system's firmware / BIOS 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 178c2ecf20Sopenharmony_ci#include <linux/fs.h> 188c2ecf20Sopenharmony_ci#include <linux/security.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/tpm_eventlog.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "../tpm.h" 238c2ecf20Sopenharmony_ci#include "common.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int tpm_bios_measurements_open(struct inode *inode, 268c2ecf20Sopenharmony_ci struct file *file) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci int err; 298c2ecf20Sopenharmony_ci struct seq_file *seq; 308c2ecf20Sopenharmony_ci struct tpm_chip_seqops *chip_seqops; 318c2ecf20Sopenharmony_ci const struct seq_operations *seqops; 328c2ecf20Sopenharmony_ci struct tpm_chip *chip; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci inode_lock(inode); 358c2ecf20Sopenharmony_ci if (!inode->i_private) { 368c2ecf20Sopenharmony_ci inode_unlock(inode); 378c2ecf20Sopenharmony_ci return -ENODEV; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci chip_seqops = (struct tpm_chip_seqops *)inode->i_private; 408c2ecf20Sopenharmony_ci seqops = chip_seqops->seqops; 418c2ecf20Sopenharmony_ci chip = chip_seqops->chip; 428c2ecf20Sopenharmony_ci get_device(&chip->dev); 438c2ecf20Sopenharmony_ci inode_unlock(inode); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* now register seq file */ 468c2ecf20Sopenharmony_ci err = seq_open(file, seqops); 478c2ecf20Sopenharmony_ci if (!err) { 488c2ecf20Sopenharmony_ci seq = file->private_data; 498c2ecf20Sopenharmony_ci seq->private = chip; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return err; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int tpm_bios_measurements_release(struct inode *inode, 568c2ecf20Sopenharmony_ci struct file *file) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct seq_file *seq = (struct seq_file *)file->private_data; 598c2ecf20Sopenharmony_ci struct tpm_chip *chip = (struct tpm_chip *)seq->private; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci put_device(&chip->dev); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return seq_release(inode, file); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const struct file_operations tpm_bios_measurements_ops = { 678c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 688c2ecf20Sopenharmony_ci .open = tpm_bios_measurements_open, 698c2ecf20Sopenharmony_ci .read = seq_read, 708c2ecf20Sopenharmony_ci .llseek = seq_lseek, 718c2ecf20Sopenharmony_ci .release = tpm_bios_measurements_release, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int tpm_read_log(struct tpm_chip *chip) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci int rc; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (chip->log.bios_event_log != NULL) { 798c2ecf20Sopenharmony_ci dev_dbg(&chip->dev, 808c2ecf20Sopenharmony_ci "%s: ERROR - event log already initialized\n", 818c2ecf20Sopenharmony_ci __func__); 828c2ecf20Sopenharmony_ci return -EFAULT; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci rc = tpm_read_log_acpi(chip); 868c2ecf20Sopenharmony_ci if (rc != -ENODEV) 878c2ecf20Sopenharmony_ci return rc; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci rc = tpm_read_log_efi(chip); 908c2ecf20Sopenharmony_ci if (rc != -ENODEV) 918c2ecf20Sopenharmony_ci return rc; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return tpm_read_log_of(chip); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * tpm_bios_log_setup() - Read the event log from the firmware 988c2ecf20Sopenharmony_ci * @chip: TPM chip to use. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * If an event log is found then the securityfs files are setup to 1018c2ecf20Sopenharmony_ci * export it to userspace, otherwise nothing is done. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_civoid tpm_bios_log_setup(struct tpm_chip *chip) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci const char *name = dev_name(&chip->dev); 1068c2ecf20Sopenharmony_ci unsigned int cnt; 1078c2ecf20Sopenharmony_ci int log_version; 1088c2ecf20Sopenharmony_ci int rc = 0; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_VIRTUAL) 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci rc = tpm_read_log(chip); 1148c2ecf20Sopenharmony_ci if (rc < 0) 1158c2ecf20Sopenharmony_ci return; 1168c2ecf20Sopenharmony_ci log_version = rc; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci cnt = 0; 1198c2ecf20Sopenharmony_ci chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); 1208c2ecf20Sopenharmony_ci /* NOTE: securityfs_create_dir can return ENODEV if securityfs is 1218c2ecf20Sopenharmony_ci * compiled out. The caller should ignore the ENODEV return code. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if (IS_ERR(chip->bios_dir[cnt])) 1248c2ecf20Sopenharmony_ci goto err; 1258c2ecf20Sopenharmony_ci cnt++; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci chip->bin_log_seqops.chip = chip; 1288c2ecf20Sopenharmony_ci if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) 1298c2ecf20Sopenharmony_ci chip->bin_log_seqops.seqops = 1308c2ecf20Sopenharmony_ci &tpm2_binary_b_measurements_seqops; 1318c2ecf20Sopenharmony_ci else 1328c2ecf20Sopenharmony_ci chip->bin_log_seqops.seqops = 1338c2ecf20Sopenharmony_ci &tpm1_binary_b_measurements_seqops; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci chip->bios_dir[cnt] = 1378c2ecf20Sopenharmony_ci securityfs_create_file("binary_bios_measurements", 1388c2ecf20Sopenharmony_ci 0440, chip->bios_dir[0], 1398c2ecf20Sopenharmony_ci (void *)&chip->bin_log_seqops, 1408c2ecf20Sopenharmony_ci &tpm_bios_measurements_ops); 1418c2ecf20Sopenharmony_ci if (IS_ERR(chip->bios_dir[cnt])) 1428c2ecf20Sopenharmony_ci goto err; 1438c2ecf20Sopenharmony_ci cnt++; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci chip->ascii_log_seqops.chip = chip; 1488c2ecf20Sopenharmony_ci chip->ascii_log_seqops.seqops = 1498c2ecf20Sopenharmony_ci &tpm1_ascii_b_measurements_seqops; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci chip->bios_dir[cnt] = 1528c2ecf20Sopenharmony_ci securityfs_create_file("ascii_bios_measurements", 1538c2ecf20Sopenharmony_ci 0440, chip->bios_dir[0], 1548c2ecf20Sopenharmony_ci (void *)&chip->ascii_log_seqops, 1558c2ecf20Sopenharmony_ci &tpm_bios_measurements_ops); 1568c2ecf20Sopenharmony_ci if (IS_ERR(chip->bios_dir[cnt])) 1578c2ecf20Sopenharmony_ci goto err; 1588c2ecf20Sopenharmony_ci cnt++; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cierr: 1648c2ecf20Sopenharmony_ci chip->bios_dir[cnt] = NULL; 1658c2ecf20Sopenharmony_ci tpm_bios_log_teardown(chip); 1668c2ecf20Sopenharmony_ci return; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_civoid tpm_bios_log_teardown(struct tpm_chip *chip) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci int i; 1728c2ecf20Sopenharmony_ci struct inode *inode; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* securityfs_remove currently doesn't take care of handling sync 1758c2ecf20Sopenharmony_ci * between removal and opening of pseudo files. To handle this, a 1768c2ecf20Sopenharmony_ci * workaround is added by making i_private = NULL here during removal 1778c2ecf20Sopenharmony_ci * and to check it during open(), both within inode_lock()/unlock(). 1788c2ecf20Sopenharmony_ci * This design ensures that open() either safely gets kref or fails. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) { 1818c2ecf20Sopenharmony_ci if (chip->bios_dir[i]) { 1828c2ecf20Sopenharmony_ci inode = d_inode(chip->bios_dir[i]); 1838c2ecf20Sopenharmony_ci inode_lock(inode); 1848c2ecf20Sopenharmony_ci inode->i_private = NULL; 1858c2ecf20Sopenharmony_ci inode_unlock(inode); 1868c2ecf20Sopenharmony_ci securityfs_remove(chip->bios_dir[i]); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci} 190