Skip to content

Commit

Permalink
Merge tag 'tpmdd-next-v5.12-rc1-v2' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/jarkko/linux-tpmdd

Pull tpm updates from Jarkko Sakkinen:
 "New features:

   - Cr50 I2C TPM driver

   - sysfs exports of PCR registers in TPM 2.0 chips

  Bug fixes:

   - bug fixes for tpm_tis driver, which had a racy wait for hardware
     state change to be ready to send a command to the TPM chip. The bug
     has existed already since 2006, but has only made itself known in
     recent past. This is the same as the "last time" :-)

   - Otherwise there's bunch of fixes for not as alarming regressions. I
     think the list is about the same as last time, except I added fixes
     for some disjoint bugs in trusted keys that I found some time ago"

* tag 'tpmdd-next-v5.12-rc1-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  KEYS: trusted: Reserve TPM for seal and unseal operations
  KEYS: trusted: Fix migratable=1 failing
  KEYS: trusted: Fix incorrect handling of tpm_get_random()
  tpm/ppi: Constify static struct attribute_group
  ABI: add sysfs description for tpm exports of PCR registers
  tpm: add sysfs exports for all banks of PCR registers
  keys: Update comment for restrict_link_by_key_or_keyring_chain
  tpm: Remove tpm_dev_wq_lock
  char: tpm: add i2c driver for cr50
  tpm: Fix fall-through warnings for Clang
  tpm_tis: Clean up locality release
  tpm_tis: Fix check_locality for correct locality acquisition
  • Loading branch information
Linus Torvalds committed Feb 22, 2021
2 parents 177626c + 8c657a0 commit a2b095e
Show file tree
Hide file tree
Showing 15 changed files with 1,054 additions and 66 deletions.
14 changes: 14 additions & 0 deletions Documentation/ABI/stable/sysfs-class-tpm
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,17 @@ Description: The "tpm_version_major" property shows the TCG spec major version
Example output::

2

What: /sys/class/tpm/tpmX/pcr-H/N
Date: March 2021
KernelVersion: 5.12
Contact: linux-integrity@vger.kernel.org
Description: produces output in compact hex representation for PCR
number N from hash bank H. N is the numeric value of
the PCR number and H is the crypto string
representation of the hash

Example output::

cat /sys/class/tpm/tpm0/pcr-sha256/7
2ED93F199692DC6788EFA6A1FE74514AB9760B2A6CEEAEF6C808C13E4ABB0D42
7 changes: 4 additions & 3 deletions crypto/asymmetric_keys/restrict.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,10 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring,
* @payload: The payload of the new key.
* @trusted: A key or ring of keys that can be used to vouch for the new cert.
*
* Check the new certificate only against the key or keys passed in the data
* parameter. If one of those is the signing key and validates the new
* certificate, then mark the new certificate as being ok to link.
* Check the new certificate against the key or keys passed in the data
* parameter and against the keys already linked to the destination keyring. If
* one of those is the signing key and validates the new certificate, then mark
* the new certificate as being ok to link.
*
* Returns 0 if the new certificate was accepted, -ENOKEY if we
* couldn't find a matching parent certificate in the trusted list,
Expand Down
10 changes: 10 additions & 0 deletions drivers/char/tpm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ config TCG_TIS_SYNQUACER
To compile this driver as a module, choose M here;
the module will be called tpm_tis_synquacer.

config TCG_TIS_I2C_CR50
tristate "TPM Interface Specification 2.0 Interface (I2C - CR50)"
depends on I2C
select TCG_CR50
help
This is a driver for the Google cr50 I2C TPM interface which is a
custom microcontroller and requires a custom i2c protocol interface
to handle the limitations of the hardware. To compile this driver
as a module, choose M here; the module will be called tcg_tis_i2c_cr50.

config TCG_TIS_I2C_ATMEL
tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)"
depends on I2C
Expand Down
2 changes: 2 additions & 0 deletions drivers/char/tpm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
tpm_tis_spi-y := tpm_tis_spi_main.o
tpm_tis_spi-$(CONFIG_TCG_TIS_SPI_CR50) += tpm_tis_spi_cr50.o

obj-$(CONFIG_TCG_TIS_I2C_CR50) += tpm_tis_i2c_cr50.o

obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o
obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o
Expand Down
1 change: 1 addition & 0 deletions drivers/char/tpm/eventlog/tpm1.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
default:
break;
}
break;
default:
break;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/char/tpm/tpm-chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ static void tpm_devs_release(struct device *dev)
{
struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);

dump_stack();

/* release the master device reference */
put_device(&chip->dev);
}
Expand Down
1 change: 0 additions & 1 deletion drivers/char/tpm/tpm-dev-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include "tpm-dev.h"

static struct workqueue_struct *tpm_dev_wq;
static DEFINE_MUTEX(tpm_dev_wq_lock);

static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space,
u8 *buf, size_t bufsiz)
Expand Down
179 changes: 179 additions & 0 deletions drivers/char/tpm/tpm-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,190 @@ static const struct attribute_group tpm2_dev_group = {
.attrs = tpm2_dev_attrs,
};

struct tpm_pcr_attr {
int alg_id;
int pcr;
struct device_attribute attr;
};

#define to_tpm_pcr_attr(a) container_of(a, struct tpm_pcr_attr, attr)

static ssize_t pcr_value_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpm_pcr_attr *ha = to_tpm_pcr_attr(attr);
struct tpm_chip *chip = to_tpm_chip(dev);
struct tpm_digest digest;
int i;
int digest_size = 0;
int rc;
char *str = buf;

for (i = 0; i < chip->nr_allocated_banks; i++)
if (ha->alg_id == chip->allocated_banks[i].alg_id)
digest_size = chip->allocated_banks[i].digest_size;
/* should never happen */
if (!digest_size)
return -EINVAL;

digest.alg_id = ha->alg_id;
rc = tpm_pcr_read(chip, ha->pcr, &digest);
if (rc)
return rc;
for (i = 0; i < digest_size; i++)
str += sprintf(str, "%02X", digest.digest[i]);
str += sprintf(str, "\n");

return str - buf;
}

/*
* The following set of defines represents all the magic to build
* the per hash attribute groups for displaying each bank of PCRs.
* The only slight problem with this approach is that every PCR is
* hard coded to be present, so you don't know if an PCR is missing
* until a cat of the file returns -EINVAL
*
* Also note you must ignore checkpatch warnings in this macro
* code. This is deep macro magic that checkpatch.pl doesn't
* understand.
*/

/* Note, this must match TPM2_PLATFORM_PCR which is fixed at 24. */
#define _TPM_HELPER(_alg, _hash, F) \
F(_alg, _hash, 0) \
F(_alg, _hash, 1) \
F(_alg, _hash, 2) \
F(_alg, _hash, 3) \
F(_alg, _hash, 4) \
F(_alg, _hash, 5) \
F(_alg, _hash, 6) \
F(_alg, _hash, 7) \
F(_alg, _hash, 8) \
F(_alg, _hash, 9) \
F(_alg, _hash, 10) \
F(_alg, _hash, 11) \
F(_alg, _hash, 12) \
F(_alg, _hash, 13) \
F(_alg, _hash, 14) \
F(_alg, _hash, 15) \
F(_alg, _hash, 16) \
F(_alg, _hash, 17) \
F(_alg, _hash, 18) \
F(_alg, _hash, 19) \
F(_alg, _hash, 20) \
F(_alg, _hash, 21) \
F(_alg, _hash, 22) \
F(_alg, _hash, 23)

/* ignore checkpatch warning about trailing ; in macro. */
#define PCR_ATTR(_alg, _hash, _pcr) \
static struct tpm_pcr_attr dev_attr_pcr_##_hash##_##_pcr = { \
.alg_id = _alg, \
.pcr = _pcr, \
.attr = { \
.attr = { \
.name = __stringify(_pcr), \
.mode = 0444 \
}, \
.show = pcr_value_show \
} \
};

#define PCR_ATTRS(_alg, _hash) \
_TPM_HELPER(_alg, _hash, PCR_ATTR)

/* ignore checkpatch warning about trailing , in macro. */
#define PCR_ATTR_VAL(_alg, _hash, _pcr) \
&dev_attr_pcr_##_hash##_##_pcr.attr.attr,

#define PCR_ATTR_GROUP_ARRAY(_alg, _hash) \
static struct attribute *pcr_group_attrs_##_hash[] = { \
_TPM_HELPER(_alg, _hash, PCR_ATTR_VAL) \
NULL \
}

#define PCR_ATTR_GROUP(_alg, _hash) \
static struct attribute_group pcr_group_##_hash = { \
.name = "pcr-" __stringify(_hash), \
.attrs = pcr_group_attrs_##_hash \
}

#define PCR_ATTR_BUILD(_alg, _hash) \
PCR_ATTRS(_alg, _hash) \
PCR_ATTR_GROUP_ARRAY(_alg, _hash); \
PCR_ATTR_GROUP(_alg, _hash)
/*
* End of macro structure to build an attribute group containing 24
* PCR value files for each supported hash algorithm
*/

/*
* The next set of macros implements the cleverness for each hash to
* build a static attribute group called pcr_group_<hash> which can be
* added to chip->groups[].
*
* The first argument is the TPM algorithm id and the second is the
* hash used as both the suffix and the group name. Note: the group
* name is a directory in the top level tpm class with the name
* pcr-<hash>, so it must not clash with any other names already
* in the sysfs directory.
*/
PCR_ATTR_BUILD(TPM_ALG_SHA1, sha1);
PCR_ATTR_BUILD(TPM_ALG_SHA256, sha256);
PCR_ATTR_BUILD(TPM_ALG_SHA384, sha384);
PCR_ATTR_BUILD(TPM_ALG_SHA512, sha512);
PCR_ATTR_BUILD(TPM_ALG_SM3_256, sm3);


void tpm_sysfs_add_device(struct tpm_chip *chip)
{
int i;

WARN_ON(chip->groups_cnt != 0);

if (chip->flags & TPM_CHIP_FLAG_TPM2)
chip->groups[chip->groups_cnt++] = &tpm2_dev_group;
else
chip->groups[chip->groups_cnt++] = &tpm1_dev_group;

/* add one group for each bank hash */
for (i = 0; i < chip->nr_allocated_banks; i++) {
switch (chip->allocated_banks[i].alg_id) {
case TPM_ALG_SHA1:
chip->groups[chip->groups_cnt++] = &pcr_group_sha1;
break;
case TPM_ALG_SHA256:
chip->groups[chip->groups_cnt++] = &pcr_group_sha256;
break;
case TPM_ALG_SHA384:
chip->groups[chip->groups_cnt++] = &pcr_group_sha384;
break;
case TPM_ALG_SHA512:
chip->groups[chip->groups_cnt++] = &pcr_group_sha512;
break;
case TPM_ALG_SM3_256:
chip->groups[chip->groups_cnt++] = &pcr_group_sm3;
break;
default:
/*
* If triggers, send a patch to add both a
* PCR_ATTR_BUILD() macro above for the
* missing algorithm as well as an additional
* case in this switch statement.
*/
dev_err(&chip->dev,
"TPM with unsupported bank algorithm 0x%04x",
chip->allocated_banks[i].alg_id);
break;
}
}

/*
* This will only trigger if someone has added an additional
* hash to the tpm_algorithms enum without incrementing
* TPM_MAX_HASHES.
*/
WARN_ON(chip->groups_cnt > TPM_MAX_HASHES + 1);
}
4 changes: 0 additions & 4 deletions drivers/char/tpm/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,6 @@ extern const struct file_operations tpmrm_fops;
extern struct idr dev_nums_idr;

ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz);
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
size_t min_rsp_body_length, const char *desc);
int tpm_get_timeouts(struct tpm_chip *);
int tpm_auto_startup(struct tpm_chip *chip);

Expand Down Expand Up @@ -194,8 +192,6 @@ static inline void tpm_msleep(unsigned int delay_msec)
int tpm_chip_start(struct tpm_chip *chip);
void tpm_chip_stop(struct tpm_chip *chip);
struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
__must_check int tpm_try_get_ops(struct tpm_chip *chip);
void tpm_put_ops(struct tpm_chip *chip);

struct tpm_chip *tpm_chip_alloc(struct device *dev,
const struct tpm_class_ops *ops);
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/tpm/tpm_ppi.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ static struct attribute *ppi_attrs[] = {
&dev_attr_tcg_operations.attr,
&dev_attr_vs_operations.attr, NULL,
};
static struct attribute_group ppi_attr_grp = {
static const struct attribute_group ppi_attr_grp = {
.name = "ppi",
.attrs = ppi_attrs
};
Expand Down
50 changes: 3 additions & 47 deletions drivers/char/tpm/tpm_tis_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ static bool check_locality(struct tpm_chip *chip, int l)
if (rc < 0)
return false;

if ((access & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
if ((access & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID
| TPM_ACCESS_REQUEST_USE)) ==
(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
priv->locality = l;
return true;
Expand All @@ -134,58 +135,13 @@ static bool check_locality(struct tpm_chip *chip, int l)
return false;
}

static bool locality_inactive(struct tpm_chip *chip, int l)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc;
u8 access;

rc = tpm_tis_read8(priv, TPM_ACCESS(l), &access);
if (rc < 0)
return false;

if ((access & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
== TPM_ACCESS_VALID)
return true;

return false;
}

static int release_locality(struct tpm_chip *chip, int l)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
unsigned long stop, timeout;
long rc;

tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);

stop = jiffies + chip->timeout_a;

if (chip->flags & TPM_CHIP_FLAG_IRQ) {
again:
timeout = stop - jiffies;
if ((long)timeout <= 0)
return -1;

rc = wait_event_interruptible_timeout(priv->int_queue,
(locality_inactive(chip, l)),
timeout);

if (rc > 0)
return 0;

if (rc == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
}
} else {
do {
if (locality_inactive(chip, l))
return 0;
tpm_msleep(TPM_TIMEOUT);
} while (time_before(jiffies, stop));
}
return -1;
return 0;
}

static int request_locality(struct tpm_chip *chip, int l)
Expand Down
Loading

0 comments on commit a2b095e

Please sign in to comment.