linux/drivers/char/tpm/tpm-sysfs.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004 IBM Corporation
   3 * Authors:
   4 * Leendert van Doorn <leendert@watson.ibm.com>
   5 * Dave Safford <safford@watson.ibm.com>
   6 * Reiner Sailer <sailer@watson.ibm.com>
   7 * Kylene Hall <kjhall@us.ibm.com>
   8 *
   9 * Copyright (C) 2013 Obsidian Research Corp
  10 * Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
  11 *
  12 * sysfs filesystem inspection interface to the TPM
  13 *
  14 * This program is free software; you can redistribute it and/or
  15 * modify it under the terms of the GNU General Public License as
  16 * published by the Free Software Foundation, version 2 of the
  17 * License.
  18 *
  19 */
  20#include <linux/device.h>
  21#include "tpm.h"
  22
  23#define READ_PUBEK_RESULT_SIZE 314
  24#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
  25#define TPM_ORD_READPUBEK 124
  26static const struct tpm_input_header tpm_readpubek_header = {
  27        .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
  28        .length = cpu_to_be32(30),
  29        .ordinal = cpu_to_be32(TPM_ORD_READPUBEK)
  30};
  31static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
  32                          char *buf)
  33{
  34        u8 *data;
  35        struct tpm_cmd_t tpm_cmd;
  36        ssize_t err;
  37        int i, rc;
  38        char *str = buf;
  39        struct tpm_chip *chip = to_tpm_chip(dev);
  40
  41        memset(&tpm_cmd, 0, sizeof(tpm_cmd));
  42
  43        tpm_cmd.header.in = tpm_readpubek_header;
  44        err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
  45                               READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
  46                               "attempting to read the PUBEK");
  47        if (err)
  48                goto out;
  49
  50        /*
  51           ignore header 10 bytes
  52           algorithm 32 bits (1 == RSA )
  53           encscheme 16 bits
  54           sigscheme 16 bits
  55           parameters (RSA 12->bytes: keybit, #primes, expbit)
  56           keylenbytes 32 bits
  57           256 byte modulus
  58           ignore checksum 20 bytes
  59         */
  60        data = tpm_cmd.params.readpubek_out_buffer;
  61        str +=
  62            sprintf(str,
  63                    "Algorithm: %02X %02X %02X %02X\n"
  64                    "Encscheme: %02X %02X\n"
  65                    "Sigscheme: %02X %02X\n"
  66                    "Parameters: %02X %02X %02X %02X "
  67                    "%02X %02X %02X %02X "
  68                    "%02X %02X %02X %02X\n"
  69                    "Modulus length: %d\n"
  70                    "Modulus:\n",
  71                    data[0], data[1], data[2], data[3],
  72                    data[4], data[5],
  73                    data[6], data[7],
  74                    data[12], data[13], data[14], data[15],
  75                    data[16], data[17], data[18], data[19],
  76                    data[20], data[21], data[22], data[23],
  77                    be32_to_cpu(*((__be32 *) (data + 24))));
  78
  79        for (i = 0; i < 256; i++) {
  80                str += sprintf(str, "%02X ", data[i + 28]);
  81                if ((i + 1) % 16 == 0)
  82                        str += sprintf(str, "\n");
  83        }
  84out:
  85        rc = str - buf;
  86        return rc;
  87}
  88static DEVICE_ATTR_RO(pubek);
  89
  90static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
  91                         char *buf)
  92{
  93        cap_t cap;
  94        u8 digest[TPM_DIGEST_SIZE];
  95        ssize_t rc;
  96        int i, j, num_pcrs;
  97        char *str = buf;
  98        struct tpm_chip *chip = to_tpm_chip(dev);
  99
 100        rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap,
 101                        "attempting to determine the number of PCRS",
 102                        sizeof(cap.num_pcrs));
 103        if (rc)
 104                return 0;
 105
 106        num_pcrs = be32_to_cpu(cap.num_pcrs);
 107        for (i = 0; i < num_pcrs; i++) {
 108                rc = tpm_pcr_read_dev(chip, i, digest);
 109                if (rc)
 110                        break;
 111                str += sprintf(str, "PCR-%02d: ", i);
 112                for (j = 0; j < TPM_DIGEST_SIZE; j++)
 113                        str += sprintf(str, "%02X ", digest[j]);
 114                str += sprintf(str, "\n");
 115        }
 116        return str - buf;
 117}
 118static DEVICE_ATTR_RO(pcrs);
 119
 120static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
 121                     char *buf)
 122{
 123        cap_t cap;
 124        ssize_t rc;
 125
 126        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
 127                        "attempting to determine the permanent enabled state",
 128                        sizeof(cap.perm_flags));
 129        if (rc)
 130                return 0;
 131
 132        rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
 133        return rc;
 134}
 135static DEVICE_ATTR_RO(enabled);
 136
 137static ssize_t active_show(struct device *dev, struct device_attribute *attr,
 138                    char *buf)
 139{
 140        cap_t cap;
 141        ssize_t rc;
 142
 143        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
 144                        "attempting to determine the permanent active state",
 145                        sizeof(cap.perm_flags));
 146        if (rc)
 147                return 0;
 148
 149        rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
 150        return rc;
 151}
 152static DEVICE_ATTR_RO(active);
 153
 154static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
 155                          char *buf)
 156{
 157        cap_t cap;
 158        ssize_t rc;
 159
 160        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
 161                        "attempting to determine the owner state",
 162                        sizeof(cap.owned));
 163        if (rc)
 164                return 0;
 165
 166        rc = sprintf(buf, "%d\n", cap.owned);
 167        return rc;
 168}
 169static DEVICE_ATTR_RO(owned);
 170
 171static ssize_t temp_deactivated_show(struct device *dev,
 172                                     struct device_attribute *attr, char *buf)
 173{
 174        cap_t cap;
 175        ssize_t rc;
 176
 177        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
 178                        "attempting to determine the temporary state",
 179                        sizeof(cap.stclear_flags));
 180        if (rc)
 181                return 0;
 182
 183        rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
 184        return rc;
 185}
 186static DEVICE_ATTR_RO(temp_deactivated);
 187
 188static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
 189                         char *buf)
 190{
 191        struct tpm_chip *chip = to_tpm_chip(dev);
 192        cap_t cap;
 193        ssize_t rc;
 194        char *str = buf;
 195
 196        rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
 197                        "attempting to determine the manufacturer",
 198                        sizeof(cap.manufacturer_id));
 199        if (rc)
 200                return 0;
 201        str += sprintf(str, "Manufacturer: 0x%x\n",
 202                       be32_to_cpu(cap.manufacturer_id));
 203
 204        /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
 205        rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap,
 206                        "attempting to determine the 1.2 version",
 207                        sizeof(cap.tpm_version_1_2));
 208        if (!rc) {
 209                str += sprintf(str,
 210                               "TCG version: %d.%d\nFirmware version: %d.%d\n",
 211                               cap.tpm_version_1_2.Major,
 212                               cap.tpm_version_1_2.Minor,
 213                               cap.tpm_version_1_2.revMajor,
 214                               cap.tpm_version_1_2.revMinor);
 215        } else {
 216                /* Otherwise just use TPM_STRUCT_VER */
 217                rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
 218                                "attempting to determine the 1.1 version",
 219                                sizeof(cap.tpm_version));
 220                if (rc)
 221                        return 0;
 222                str += sprintf(str,
 223                               "TCG version: %d.%d\nFirmware version: %d.%d\n",
 224                               cap.tpm_version.Major,
 225                               cap.tpm_version.Minor,
 226                               cap.tpm_version.revMajor,
 227                               cap.tpm_version.revMinor);
 228        }
 229
 230        return str - buf;
 231}
 232static DEVICE_ATTR_RO(caps);
 233
 234static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
 235                            const char *buf, size_t count)
 236{
 237        struct tpm_chip *chip = to_tpm_chip(dev);
 238        if (chip == NULL)
 239                return 0;
 240
 241        chip->ops->cancel(chip);
 242        return count;
 243}
 244static DEVICE_ATTR_WO(cancel);
 245
 246static ssize_t durations_show(struct device *dev, struct device_attribute *attr,
 247                              char *buf)
 248{
 249        struct tpm_chip *chip = to_tpm_chip(dev);
 250
 251        if (chip->duration[TPM_LONG] == 0)
 252                return 0;
 253
 254        return sprintf(buf, "%d %d %d [%s]\n",
 255                       jiffies_to_usecs(chip->duration[TPM_SHORT]),
 256                       jiffies_to_usecs(chip->duration[TPM_MEDIUM]),
 257                       jiffies_to_usecs(chip->duration[TPM_LONG]),
 258                       chip->duration_adjusted
 259                       ? "adjusted" : "original");
 260}
 261static DEVICE_ATTR_RO(durations);
 262
 263static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr,
 264                             char *buf)
 265{
 266        struct tpm_chip *chip = to_tpm_chip(dev);
 267
 268        return sprintf(buf, "%d %d %d %d [%s]\n",
 269                       jiffies_to_usecs(chip->timeout_a),
 270                       jiffies_to_usecs(chip->timeout_b),
 271                       jiffies_to_usecs(chip->timeout_c),
 272                       jiffies_to_usecs(chip->timeout_d),
 273                       chip->timeout_adjusted
 274                       ? "adjusted" : "original");
 275}
 276static DEVICE_ATTR_RO(timeouts);
 277
 278static struct attribute *tpm_dev_attrs[] = {
 279        &dev_attr_pubek.attr,
 280        &dev_attr_pcrs.attr,
 281        &dev_attr_enabled.attr,
 282        &dev_attr_active.attr,
 283        &dev_attr_owned.attr,
 284        &dev_attr_temp_deactivated.attr,
 285        &dev_attr_caps.attr,
 286        &dev_attr_cancel.attr,
 287        &dev_attr_durations.attr,
 288        &dev_attr_timeouts.attr,
 289        NULL,
 290};
 291
 292static const struct attribute_group tpm_dev_group = {
 293        .attrs = tpm_dev_attrs,
 294};
 295
 296void tpm_sysfs_add_device(struct tpm_chip *chip)
 297{
 298        /* XXX: If you wish to remove this restriction, you must first update
 299         * tpm_sysfs to explicitly lock chip->ops.
 300         */
 301        if (chip->flags & TPM_CHIP_FLAG_TPM2)
 302                return;
 303
 304        /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
 305         * is called before ops is null'd and the sysfs core synchronizes this
 306         * removal so that no callbacks are running or can run again
 307         */
 308        WARN_ON(chip->groups_cnt != 0);
 309        chip->groups[chip->groups_cnt++] = &tpm_dev_group;
 310}
 311