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