linux/drivers/char/tpm/eventlog/common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2005, 2012 IBM Corporation
   4 *
   5 * Authors:
   6 *      Kent Yoder <key@linux.vnet.ibm.com>
   7 *      Seiji Munetoh <munetoh@jp.ibm.com>
   8 *      Stefan Berger <stefanb@us.ibm.com>
   9 *      Reiner Sailer <sailer@watson.ibm.com>
  10 *      Kylene Hall <kjhall@us.ibm.com>
  11 *      Nayna Jain <nayna@linux.vnet.ibm.com>
  12 *
  13 * Access to the event log created by a system's firmware / BIOS
  14 */
  15
  16#include <linux/seq_file.h>
  17#include <linux/fs.h>
  18#include <linux/security.h>
  19#include <linux/module.h>
  20#include <linux/tpm_eventlog.h>
  21
  22#include "../tpm.h"
  23#include "common.h"
  24
  25static int tpm_bios_measurements_open(struct inode *inode,
  26                                            struct file *file)
  27{
  28        int err;
  29        struct seq_file *seq;
  30        struct tpm_chip_seqops *chip_seqops;
  31        const struct seq_operations *seqops;
  32        struct tpm_chip *chip;
  33
  34        inode_lock(inode);
  35        if (!inode->i_private) {
  36                inode_unlock(inode);
  37                return -ENODEV;
  38        }
  39        chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
  40        seqops = chip_seqops->seqops;
  41        chip = chip_seqops->chip;
  42        get_device(&chip->dev);
  43        inode_unlock(inode);
  44
  45        /* now register seq file */
  46        err = seq_open(file, seqops);
  47        if (!err) {
  48                seq = file->private_data;
  49                seq->private = chip;
  50        }
  51
  52        return err;
  53}
  54
  55static int tpm_bios_measurements_release(struct inode *inode,
  56                                         struct file *file)
  57{
  58        struct seq_file *seq = (struct seq_file *)file->private_data;
  59        struct tpm_chip *chip = (struct tpm_chip *)seq->private;
  60
  61        put_device(&chip->dev);
  62
  63        return seq_release(inode, file);
  64}
  65
  66static const struct file_operations tpm_bios_measurements_ops = {
  67        .owner = THIS_MODULE,
  68        .open = tpm_bios_measurements_open,
  69        .read = seq_read,
  70        .llseek = seq_lseek,
  71        .release = tpm_bios_measurements_release,
  72};
  73
  74static int tpm_read_log(struct tpm_chip *chip)
  75{
  76        int rc;
  77
  78        if (chip->log.bios_event_log != NULL) {
  79                dev_dbg(&chip->dev,
  80                        "%s: ERROR - event log already initialized\n",
  81                        __func__);
  82                return -EFAULT;
  83        }
  84
  85        rc = tpm_read_log_acpi(chip);
  86        if (rc != -ENODEV)
  87                return rc;
  88
  89        rc = tpm_read_log_efi(chip);
  90        if (rc != -ENODEV)
  91                return rc;
  92
  93        return tpm_read_log_of(chip);
  94}
  95
  96/*
  97 * tpm_bios_log_setup() - Read the event log from the firmware
  98 * @chip: TPM chip to use.
  99 *
 100 * If an event log is found then the securityfs files are setup to
 101 * export it to userspace, otherwise nothing is done.
 102 */
 103void tpm_bios_log_setup(struct tpm_chip *chip)
 104{
 105        const char *name = dev_name(&chip->dev);
 106        unsigned int cnt;
 107        int log_version;
 108        int rc = 0;
 109
 110        if (chip->flags & TPM_CHIP_FLAG_VIRTUAL)
 111                return;
 112
 113        rc = tpm_read_log(chip);
 114        if (rc < 0)
 115                return;
 116        log_version = rc;
 117
 118        cnt = 0;
 119        chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
 120        /* NOTE: securityfs_create_dir can return ENODEV if securityfs is
 121         * compiled out. The caller should ignore the ENODEV return code.
 122         */
 123        if (IS_ERR(chip->bios_dir[cnt]))
 124                goto err;
 125        cnt++;
 126
 127        chip->bin_log_seqops.chip = chip;
 128        if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
 129                chip->bin_log_seqops.seqops =
 130                        &tpm2_binary_b_measurements_seqops;
 131        else
 132                chip->bin_log_seqops.seqops =
 133                        &tpm1_binary_b_measurements_seqops;
 134
 135
 136        chip->bios_dir[cnt] =
 137            securityfs_create_file("binary_bios_measurements",
 138                                   0440, chip->bios_dir[0],
 139                                   (void *)&chip->bin_log_seqops,
 140                                   &tpm_bios_measurements_ops);
 141        if (IS_ERR(chip->bios_dir[cnt]))
 142                goto err;
 143        cnt++;
 144
 145        if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
 146
 147                chip->ascii_log_seqops.chip = chip;
 148                chip->ascii_log_seqops.seqops =
 149                        &tpm1_ascii_b_measurements_seqops;
 150
 151                chip->bios_dir[cnt] =
 152                        securityfs_create_file("ascii_bios_measurements",
 153                                               0440, chip->bios_dir[0],
 154                                               (void *)&chip->ascii_log_seqops,
 155                                               &tpm_bios_measurements_ops);
 156                if (IS_ERR(chip->bios_dir[cnt]))
 157                        goto err;
 158                cnt++;
 159        }
 160
 161        return;
 162
 163err:
 164        chip->bios_dir[cnt] = NULL;
 165        tpm_bios_log_teardown(chip);
 166        return;
 167}
 168
 169void tpm_bios_log_teardown(struct tpm_chip *chip)
 170{
 171        int i;
 172        struct inode *inode;
 173
 174        /* securityfs_remove currently doesn't take care of handling sync
 175         * between removal and opening of pseudo files. To handle this, a
 176         * workaround is added by making i_private = NULL here during removal
 177         * and to check it during open(), both within inode_lock()/unlock().
 178         * This design ensures that open() either safely gets kref or fails.
 179         */
 180        for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
 181                if (chip->bios_dir[i]) {
 182                        inode = d_inode(chip->bios_dir[i]);
 183                        inode_lock(inode);
 184                        inode->i_private = NULL;
 185                        inode_unlock(inode);
 186                        securityfs_remove(chip->bios_dir[i]);
 187                }
 188        }
 189}
 190