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        rc = tpm_read_log(chip);
 111        if (rc < 0)
 112                return;
 113        log_version = rc;
 114
 115        cnt = 0;
 116        chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
 117        /* NOTE: securityfs_create_dir can return ENODEV if securityfs is
 118         * compiled out. The caller should ignore the ENODEV return code.
 119         */
 120        if (IS_ERR(chip->bios_dir[cnt]))
 121                goto err;
 122        cnt++;
 123
 124        chip->bin_log_seqops.chip = chip;
 125        if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
 126                chip->bin_log_seqops.seqops =
 127                        &tpm2_binary_b_measurements_seqops;
 128        else
 129                chip->bin_log_seqops.seqops =
 130                        &tpm1_binary_b_measurements_seqops;
 131
 132
 133        chip->bios_dir[cnt] =
 134            securityfs_create_file("binary_bios_measurements",
 135                                   0440, chip->bios_dir[0],
 136                                   (void *)&chip->bin_log_seqops,
 137                                   &tpm_bios_measurements_ops);
 138        if (IS_ERR(chip->bios_dir[cnt]))
 139                goto err;
 140        cnt++;
 141
 142        if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
 143
 144                chip->ascii_log_seqops.chip = chip;
 145                chip->ascii_log_seqops.seqops =
 146                        &tpm1_ascii_b_measurements_seqops;
 147
 148                chip->bios_dir[cnt] =
 149                        securityfs_create_file("ascii_bios_measurements",
 150                                               0440, chip->bios_dir[0],
 151                                               (void *)&chip->ascii_log_seqops,
 152                                               &tpm_bios_measurements_ops);
 153                if (IS_ERR(chip->bios_dir[cnt]))
 154                        goto err;
 155                cnt++;
 156        }
 157
 158        return;
 159
 160err:
 161        chip->bios_dir[cnt] = NULL;
 162        tpm_bios_log_teardown(chip);
 163        return;
 164}
 165
 166void tpm_bios_log_teardown(struct tpm_chip *chip)
 167{
 168        int i;
 169        struct inode *inode;
 170
 171        /* securityfs_remove currently doesn't take care of handling sync
 172         * between removal and opening of pseudo files. To handle this, a
 173         * workaround is added by making i_private = NULL here during removal
 174         * and to check it during open(), both within inode_lock()/unlock().
 175         * This design ensures that open() either safely gets kref or fails.
 176         */
 177        for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
 178                if (chip->bios_dir[i]) {
 179                        inode = d_inode(chip->bios_dir[i]);
 180                        inode_lock(inode);
 181                        inode->i_private = NULL;
 182                        inode_unlock(inode);
 183                        securityfs_remove(chip->bios_dir[i]);
 184                }
 185        }
 186}
 187