linux-stable/drivers/char/tpm/tpm2-cmd.c

788 lines
19 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014, 2015 Intel Corporation
*
* Authors:
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* This file contains TPM2 protocol implementations of the commands
* used by the kernel internally.
*/
#include "tpm.h"
#include <crypto/hash_info.h>
static struct tpm2_hash tpm2_hash_map[] = {
{HASH_ALGO_SHA1, TPM_ALG_SHA1},
{HASH_ALGO_SHA256, TPM_ALG_SHA256},
{HASH_ALGO_SHA384, TPM_ALG_SHA384},
{HASH_ALGO_SHA512, TPM_ALG_SHA512},
{HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
};
int tpm2_get_timeouts(struct tpm_chip *chip)
{
/* Fixed timeouts for TPM2 */
chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
/* PTP spec timeouts */
chip->duration[TPM_SHORT] = msecs_to_jiffies(TPM2_DURATION_SHORT);
chip->duration[TPM_MEDIUM] = msecs_to_jiffies(TPM2_DURATION_MEDIUM);
chip->duration[TPM_LONG] = msecs_to_jiffies(TPM2_DURATION_LONG);
/* Key creation commands long timeouts */
chip->duration[TPM_LONG_LONG] =
msecs_to_jiffies(TPM2_DURATION_LONG_LONG);
chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
return 0;
}
/**
* tpm2_ordinal_duration_index() - returns an index to the chip duration table
* @ordinal: TPM command ordinal.
*
* The function returns an index to the chip duration table
* (enum tpm_duration), that describes the maximum amount of
* time the chip could take to return the result for a particular ordinal.
*
* The values of the MEDIUM, and LONG durations are taken
* from the PC Client Profile (PTP) specification (750, 2000 msec)
*
* LONG_LONG is for commands that generates keys which empirically takes
* a longer time on some systems.
*
* Return:
* * TPM_MEDIUM
* * TPM_LONG
* * TPM_LONG_LONG
* * TPM_UNDEFINED
*/
static u8 tpm2_ordinal_duration_index(u32 ordinal)
{
switch (ordinal) {
/* Startup */
case TPM2_CC_STARTUP: /* 144 */
return TPM_MEDIUM;
case TPM2_CC_SELF_TEST: /* 143 */
return TPM_LONG;
case TPM2_CC_GET_RANDOM: /* 17B */
return TPM_LONG;
case TPM2_CC_SEQUENCE_UPDATE: /* 15C */
return TPM_MEDIUM;
case TPM2_CC_SEQUENCE_COMPLETE: /* 13E */
return TPM_MEDIUM;
case TPM2_CC_EVENT_SEQUENCE_COMPLETE: /* 185 */
return TPM_MEDIUM;
case TPM2_CC_HASH_SEQUENCE_START: /* 186 */
return TPM_MEDIUM;
case TPM2_CC_VERIFY_SIGNATURE: /* 177 */
return TPM_LONG_LONG;
case TPM2_CC_PCR_EXTEND: /* 182 */
return TPM_MEDIUM;
case TPM2_CC_HIERARCHY_CONTROL: /* 121 */
return TPM_LONG;
case TPM2_CC_HIERARCHY_CHANGE_AUTH: /* 129 */
return TPM_LONG;
case TPM2_CC_GET_CAPABILITY: /* 17A */
return TPM_MEDIUM;
case TPM2_CC_NV_READ: /* 14E */
return TPM_LONG;
case TPM2_CC_CREATE_PRIMARY: /* 131 */
return TPM_LONG_LONG;
case TPM2_CC_CREATE: /* 153 */
return TPM_LONG_LONG;
case TPM2_CC_CREATE_LOADED: /* 191 */
return TPM_LONG_LONG;
default:
return TPM_UNDEFINED;
}
}
/**
* tpm2_calc_ordinal_duration() - calculate the maximum command duration
* @chip: TPM chip to use.
* @ordinal: TPM command ordinal.
*
* The function returns the maximum amount of time the chip could take
* to return the result for a particular ordinal in jiffies.
*
* Return: A maximal duration time for an ordinal in jiffies.
*/
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
{
unsigned int index;
index = tpm2_ordinal_duration_index(ordinal);
if (index != TPM_UNDEFINED)
return chip->duration[index];
else
return msecs_to_jiffies(TPM2_DURATION_DEFAULT);
}
struct tpm2_pcr_read_out {
__be32 update_cnt;
__be32 pcr_selects_cnt;
__be16 hash_alg;
u8 pcr_select_size;
u8 pcr_select[TPM2_PCR_SELECT_MIN];
__be32 digests_cnt;
__be16 digest_size;
u8 digest[];
} __packed;
/**
* tpm2_pcr_read() - read a PCR value
* @chip: TPM chip to use.
* @pcr_idx: index of the PCR to read.
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
* @digest: PCR bank and buffer current PCR value is written to.
* @digest_size_ptr: pointer to variable that stores the digest size.
*
* Return: Same as with tpm_transmit_cmd.
*/
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digest, u16 *digest_size_ptr)
{
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
int i;
int rc;
struct tpm_buf buf;
struct tpm2_pcr_read_out *out;
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
u16 digest_size;
u16 expected_digest_size = 0;
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
if (!digest_size_ptr) {
for (i = 0; i < chip->nr_allocated_banks &&
chip->allocated_banks[i].alg_id != digest->alg_id; i++)
;
if (i == chip->nr_allocated_banks)
return -EINVAL;
expected_digest_size = chip->allocated_banks[i].digest_size;
}
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
if (rc)
return rc;
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
tpm_buf_append_u32(&buf, 1);
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
tpm_buf_append_u16(&buf, digest->alg_id);
tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
tpm_buf_append(&buf, (const unsigned char *)pcr_select,
sizeof(pcr_select));
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
if (rc)
goto out;
out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
digest_size = be16_to_cpu(out->digest_size);
if (digest_size > sizeof(digest->digest) ||
(!digest_size_ptr && digest_size != expected_digest_size)) {
rc = -EINVAL;
goto out;
}
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
if (digest_size_ptr)
*digest_size_ptr = digest_size;
memcpy(digest->digest, out->digest, digest_size);
out:
tpm_buf_destroy(&buf);
return rc;
}
struct tpm2_null_auth_area {
__be32 handle;
__be16 nonce_size;
u8 attributes;
__be16 auth_size;
} __packed;
/**
* tpm2_pcr_extend() - extend a PCR value
*
* @chip: TPM chip to use.
* @pcr_idx: index of the PCR.
* @digests: list of pcr banks and corresponding digest values to extend.
*
* Return: Same as with tpm_transmit_cmd.
*/
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests)
{
struct tpm_buf buf;
struct tpm2_null_auth_area auth_area;
int rc;
int i;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (rc)
return rc;
tpm_buf_append_u32(&buf, pcr_idx);
auth_area.handle = cpu_to_be32(TPM2_RS_PW);
auth_area.nonce_size = 0;
auth_area.attributes = 0;
auth_area.auth_size = 0;
tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area));
tpm_buf_append(&buf, (const unsigned char *)&auth_area,
sizeof(auth_area));
tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
for (i = 0; i < chip->nr_allocated_banks; i++) {
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
tpm_buf_append_u16(&buf, digests[i].alg_id);
tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
chip->allocated_banks[i].digest_size);
}
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
tpm_buf_destroy(&buf);
return rc;
}
struct tpm2_get_random_out {
__be16 size;
u8 buffer[TPM_MAX_RNG_DATA];
} __packed;
/**
* tpm2_get_random() - get random bytes from the TPM RNG
*
* @chip: a &tpm_chip instance
* @dest: destination buffer
* @max: the max number of random bytes to pull
*
* Return:
* size of the buffer on success,
* -errno otherwise (positive TPM return codes are masked to -EIO)
*/
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm2_get_random_out *out;
struct tpm_buf buf;
u32 recd;
u32 num_bytes = max;
int err;
int total = 0;
int retries = 5;
u8 *dest_ptr = dest;
if (!num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
err = tpm_buf_init(&buf, 0, 0);
if (err)
return err;
do {
tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM);
tpm_buf_append_u16(&buf, num_bytes);
err = tpm_transmit_cmd(chip, &buf,
offsetof(struct tpm2_get_random_out,
buffer),
"attempting get random");
if (err) {
if (err > 0)
err = -EIO;
goto out;
}
out = (struct tpm2_get_random_out *)
&buf.data[TPM_HEADER_SIZE];
recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
if (tpm_buf_length(&buf) <
TPM_HEADER_SIZE +
offsetof(struct tpm2_get_random_out, buffer) +
recd) {
err = -EFAULT;
goto out;
}
memcpy(dest_ptr, out->buffer, recd);
dest_ptr += recd;
total += recd;
num_bytes -= recd;
} while (retries-- && total < max);
tpm_buf_destroy(&buf);
return total ? total : -EIO;
out:
tpm_buf_destroy(&buf);
return err;
}
/**
* tpm2_flush_context() - execute a TPM2_FlushContext command
* @chip: TPM chip to use
* @handle: context handle
*/
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
if (rc) {
dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
handle);
return;
}
tpm_buf_append_u32(&buf, handle);
tpm_transmit_cmd(chip, &buf, 0, "flushing context");
tpm_buf_destroy(&buf);
}
EXPORT_SYMBOL_GPL(tpm2_flush_context);
struct tpm2_get_cap_out {
u8 more_data;
__be32 subcap_id;
__be32 property_cnt;
__be32 property_id;
__be32 value;
} __packed;
/**
* tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
* @chip: a &tpm_chip instance
* @property_id: property ID.
* @value: output variable.
* @desc: passed to tpm_transmit_cmd()
*
* Return:
* 0 on success,
* -errno or a TPM return code otherwise
*/
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
const char *desc)
{
struct tpm2_get_cap_out *out;
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
if (rc)
return rc;
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(&buf, property_id);
tpm_buf_append_u32(&buf, 1);
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
if (!rc) {
out = (struct tpm2_get_cap_out *)
&buf.data[TPM_HEADER_SIZE];
/*
* To prevent failing boot up of some systems, Infineon TPM2.0
* returns SUCCESS on TPM2_Startup in field upgrade mode. Also
* the TPM2_Getcapability command returns a zero length list
* in field upgrade mode.
*/
if (be32_to_cpu(out->property_cnt) > 0)
*value = be32_to_cpu(out->value);
else
rc = -ENODATA;
}
tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
/**
* tpm2_shutdown() - send a TPM shutdown command
*
* Sends a TPM shutdown command. The shutdown command is used in call
* sites where the system is going down. If it fails, there is not much
* that can be done except print an error message.
*
* @chip: a &tpm_chip instance
* @shutdown_type: TPM_SU_CLEAR or TPM_SU_STATE.
*/
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
if (rc)
return;
tpm_buf_append_u16(&buf, shutdown_type);
tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
tpm_buf_destroy(&buf);
}
/**
* tpm2_do_selftest() - ensure that all self tests have passed
*
* @chip: TPM chip to use
*
* Return: Same as with tpm_transmit_cmd.
*
tpm: React correctly to RC_TESTING from TPM 2.0 self tests The TPM can choose one of two ways to react to the TPM2_SelfTest command. It can either run all self tests synchronously and then return RC_SUCCESS once all tests were successful. Or it can choose to run the tests asynchronously and return RC_TESTING immediately while the self tests still execute in the background. The previous implementation apparently was not aware of those possibilities and attributed RC_TESTING to some prototype chips instead. With this change the return code of TPM2_SelfTest is interpreted correctly, i.e. the self test result is polled if and only if RC_TESTING is received. Unfortunately, the polling cannot be done in the most straightforward way. If RC_TESTING is received, ideally the code should now poll the selfTestDone bit in the STS register, as this avoids sending more commands, that might interrupt self tests executing in the background and thus prevent them from ever completing. But it cannot be guaranteed that this bit is correctly implemented for all devices, so the next best thing would be to use TPM2_GetTestResult to query the test result. But the response to that command can be very long, and the code currently lacks the capabilities for efficient unmarshalling, so it is difficult to execute this command. Therefore, we simply run the TPM2_SelfTest command in a loop, which should complete eventually, since we only request the execution of self tests that have not yet been done. Signed-off-by: Alexander Steffen <Alexander.Steffen@infineon.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2017-08-31 17:18:58 +00:00
* The TPM can either run all self tests synchronously and then return
* RC_SUCCESS once all tests were successful. Or it can choose to run the tests
* asynchronously and return RC_TESTING immediately while the self tests still
* execute in the background. This function handles both cases and waits until
* all tests have completed.
*/
static int tpm2_do_selftest(struct tpm_chip *chip)
{
tpm: fix intermittent failure with self tests My Nuvoton 6xx in a Dell XPS-13 has been intermittently failing to work (necessitating a reboot). The problem seems to be that the TPM gets into a state where the partial self-test doesn't return TPM_RC_SUCCESS (meaning all tests have run to completion), but instead returns TPM_RC_TESTING (meaning some tests are still running in the background). There are various theories that resending the self-test command actually causes the tests to restart and thus triggers more TPM_RC_TESTING returns until the timeout is exceeded. There are several issues here: firstly being we shouldn't slow down the boot sequence waiting for the self test to complete once the TPM backgrounds them. It will actually make available all functions that have passed and if it gets a failure return TPM_RC_FAILURE to every subsequent command. So the fix is to kick off self tests once and if they return TPM_RC_TESTING log that as a backgrounded self test and continue on. In order to prevent other tpm users from seeing any TPM_RC_TESTING returns (which it might if they send a command that needs a TPM subsystem which is still under test), we loop in tpm_transmit_cmd until either a timeout or we don't get a TPM_RC_TESTING return. Finally, there have been observations of strange returns from a partial test. One Nuvoton is occasionally returning TPM_RC_COMMAND_CODE, so treat any unexpected return from a partial self test as an indication we need to run a full self test. [jarkko.sakkinen@linux.intel.com: cleaned up some klog messages and dropped tpm_transmit_check() helper function from James' original commit.] Fixes: 2482b1bba5122 ("tpm: Trigger only missing TPM 2.0 self tests") Cc: stable@vger.kernel.org Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com>
2018-03-22 15:32:20 +00:00
struct tpm_buf buf;
int full;
int rc;
tpm: fix intermittent failure with self tests My Nuvoton 6xx in a Dell XPS-13 has been intermittently failing to work (necessitating a reboot). The problem seems to be that the TPM gets into a state where the partial self-test doesn't return TPM_RC_SUCCESS (meaning all tests have run to completion), but instead returns TPM_RC_TESTING (meaning some tests are still running in the background). There are various theories that resending the self-test command actually causes the tests to restart and thus triggers more TPM_RC_TESTING returns until the timeout is exceeded. There are several issues here: firstly being we shouldn't slow down the boot sequence waiting for the self test to complete once the TPM backgrounds them. It will actually make available all functions that have passed and if it gets a failure return TPM_RC_FAILURE to every subsequent command. So the fix is to kick off self tests once and if they return TPM_RC_TESTING log that as a backgrounded self test and continue on. In order to prevent other tpm users from seeing any TPM_RC_TESTING returns (which it might if they send a command that needs a TPM subsystem which is still under test), we loop in tpm_transmit_cmd until either a timeout or we don't get a TPM_RC_TESTING return. Finally, there have been observations of strange returns from a partial test. One Nuvoton is occasionally returning TPM_RC_COMMAND_CODE, so treat any unexpected return from a partial self test as an indication we need to run a full self test. [jarkko.sakkinen@linux.intel.com: cleaned up some klog messages and dropped tpm_transmit_check() helper function from James' original commit.] Fixes: 2482b1bba5122 ("tpm: Trigger only missing TPM 2.0 self tests") Cc: stable@vger.kernel.org Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com>
2018-03-22 15:32:20 +00:00
for (full = 0; full < 2; full++) {
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
if (rc)
return rc;
tpm: fix intermittent failure with self tests My Nuvoton 6xx in a Dell XPS-13 has been intermittently failing to work (necessitating a reboot). The problem seems to be that the TPM gets into a state where the partial self-test doesn't return TPM_RC_SUCCESS (meaning all tests have run to completion), but instead returns TPM_RC_TESTING (meaning some tests are still running in the background). There are various theories that resending the self-test command actually causes the tests to restart and thus triggers more TPM_RC_TESTING returns until the timeout is exceeded. There are several issues here: firstly being we shouldn't slow down the boot sequence waiting for the self test to complete once the TPM backgrounds them. It will actually make available all functions that have passed and if it gets a failure return TPM_RC_FAILURE to every subsequent command. So the fix is to kick off self tests once and if they return TPM_RC_TESTING log that as a backgrounded self test and continue on. In order to prevent other tpm users from seeing any TPM_RC_TESTING returns (which it might if they send a command that needs a TPM subsystem which is still under test), we loop in tpm_transmit_cmd until either a timeout or we don't get a TPM_RC_TESTING return. Finally, there have been observations of strange returns from a partial test. One Nuvoton is occasionally returning TPM_RC_COMMAND_CODE, so treat any unexpected return from a partial self test as an indication we need to run a full self test. [jarkko.sakkinen@linux.intel.com: cleaned up some klog messages and dropped tpm_transmit_check() helper function from James' original commit.] Fixes: 2482b1bba5122 ("tpm: Trigger only missing TPM 2.0 self tests") Cc: stable@vger.kernel.org Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com>
2018-03-22 15:32:20 +00:00
tpm_buf_append_u8(&buf, full);
rc = tpm_transmit_cmd(chip, &buf, 0,
tpm: fix intermittent failure with self tests My Nuvoton 6xx in a Dell XPS-13 has been intermittently failing to work (necessitating a reboot). The problem seems to be that the TPM gets into a state where the partial self-test doesn't return TPM_RC_SUCCESS (meaning all tests have run to completion), but instead returns TPM_RC_TESTING (meaning some tests are still running in the background). There are various theories that resending the self-test command actually causes the tests to restart and thus triggers more TPM_RC_TESTING returns until the timeout is exceeded. There are several issues here: firstly being we shouldn't slow down the boot sequence waiting for the self test to complete once the TPM backgrounds them. It will actually make available all functions that have passed and if it gets a failure return TPM_RC_FAILURE to every subsequent command. So the fix is to kick off self tests once and if they return TPM_RC_TESTING log that as a backgrounded self test and continue on. In order to prevent other tpm users from seeing any TPM_RC_TESTING returns (which it might if they send a command that needs a TPM subsystem which is still under test), we loop in tpm_transmit_cmd until either a timeout or we don't get a TPM_RC_TESTING return. Finally, there have been observations of strange returns from a partial test. One Nuvoton is occasionally returning TPM_RC_COMMAND_CODE, so treat any unexpected return from a partial self test as an indication we need to run a full self test. [jarkko.sakkinen@linux.intel.com: cleaned up some klog messages and dropped tpm_transmit_check() helper function from James' original commit.] Fixes: 2482b1bba5122 ("tpm: Trigger only missing TPM 2.0 self tests") Cc: stable@vger.kernel.org Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com>
2018-03-22 15:32:20 +00:00
"attempting the self test");
tpm_buf_destroy(&buf);
tpm: fix intermittent failure with self tests My Nuvoton 6xx in a Dell XPS-13 has been intermittently failing to work (necessitating a reboot). The problem seems to be that the TPM gets into a state where the partial self-test doesn't return TPM_RC_SUCCESS (meaning all tests have run to completion), but instead returns TPM_RC_TESTING (meaning some tests are still running in the background). There are various theories that resending the self-test command actually causes the tests to restart and thus triggers more TPM_RC_TESTING returns until the timeout is exceeded. There are several issues here: firstly being we shouldn't slow down the boot sequence waiting for the self test to complete once the TPM backgrounds them. It will actually make available all functions that have passed and if it gets a failure return TPM_RC_FAILURE to every subsequent command. So the fix is to kick off self tests once and if they return TPM_RC_TESTING log that as a backgrounded self test and continue on. In order to prevent other tpm users from seeing any TPM_RC_TESTING returns (which it might if they send a command that needs a TPM subsystem which is still under test), we loop in tpm_transmit_cmd until either a timeout or we don't get a TPM_RC_TESTING return. Finally, there have been observations of strange returns from a partial test. One Nuvoton is occasionally returning TPM_RC_COMMAND_CODE, so treat any unexpected return from a partial self test as an indication we need to run a full self test. [jarkko.sakkinen@linux.intel.com: cleaned up some klog messages and dropped tpm_transmit_check() helper function from James' original commit.] Fixes: 2482b1bba5122 ("tpm: Trigger only missing TPM 2.0 self tests") Cc: stable@vger.kernel.org Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com>
2018-03-22 15:32:20 +00:00
if (rc == TPM2_RC_TESTING)
rc = TPM2_RC_SUCCESS;
if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS)
return rc;
}
return rc;
}
/**
* tpm2_probe() - probe for the TPM 2.0 protocol
* @chip: a &tpm_chip instance
*
* Send an idempotent TPM 2.0 command and see whether there is TPM2 chip in the
* other end based on the response tag. The flag TPM_CHIP_FLAG_TPM2 is set by
* this function if this is the case.
*
* Return:
* 0 on success,
* -errno otherwise
*/
int tpm2_probe(struct tpm_chip *chip)
{
struct tpm_header *out;
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
if (rc)
return rc;
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
tpm_buf_append_u32(&buf, 1);
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
/* We ignore TPM return codes on purpose. */
if (rc >= 0) {
out = (struct tpm_header *)buf.data;
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
}
tpm_buf_destroy(&buf);
return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
static int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index)
{
struct tpm_bank_info *bank = chip->allocated_banks + bank_index;
struct tpm_digest digest = { .alg_id = bank->alg_id };
int i;
/*
* Avoid unnecessary PCR read operations to reduce overhead
* and obtain identifiers of the crypto subsystem.
*/
for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
enum hash_algo crypto_algo = tpm2_hash_map[i].crypto_id;
if (bank->alg_id != tpm2_hash_map[i].tpm_id)
continue;
bank->digest_size = hash_digest_size[crypto_algo];
bank->crypto_id = crypto_algo;
return 0;
}
bank->crypto_id = HASH_ALGO__LAST;
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size);
}
struct tpm2_pcr_selection {
__be16 hash_alg;
u8 size_of_select;
u8 pcr_select[3];
} __packed;
ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
{
struct tpm2_pcr_selection pcr_selection;
struct tpm_buf buf;
void *marker;
void *end;
void *pcr_select_offset;
u32 sizeof_pcr_selection;
u32 nr_possible_banks;
u32 nr_alloc_banks = 0;
u16 hash_alg;
u32 rsp_len;
int rc;
int i = 0;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
if (rc)
return rc;
tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
tpm_buf_append_u32(&buf, 0);
tpm_buf_append_u32(&buf, 1);
rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
if (rc)
goto out;
nr_possible_banks = be32_to_cpup(
(__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
chip->allocated_banks = kcalloc(nr_possible_banks,
sizeof(*chip->allocated_banks),
GFP_KERNEL);
if (!chip->allocated_banks) {
rc = -ENOMEM;
goto out;
}
marker = &buf.data[TPM_HEADER_SIZE + 9];
rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
end = &buf.data[rsp_len];
for (i = 0; i < nr_possible_banks; i++) {
pcr_select_offset = marker +
offsetof(struct tpm2_pcr_selection, size_of_select);
if (pcr_select_offset >= end) {
rc = -EFAULT;
break;
}
memcpy(&pcr_selection, marker, sizeof(pcr_selection));
hash_alg = be16_to_cpu(pcr_selection.hash_alg);
pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0,
pcr_selection.size_of_select);
if (pcr_select_offset) {
tpm: retrieve digest size of unknown algorithms with PCR read Currently, the TPM driver retrieves the digest size from a table mapping TPM algorithms identifiers to identifiers defined by the crypto subsystem. If the algorithm is not defined by the latter, the digest size can be retrieved from the output of the PCR read command. The patch modifies the definition of tpm_pcr_read() and tpm2_pcr_read() to pass the desired hash algorithm and obtain the digest size at TPM startup. Algorithms and corresponding digest sizes are stored in the new structure tpm_bank_info, member of tpm_chip, so that the information can be used by other kernel subsystems. tpm_bank_info contains: the TPM algorithm identifier, necessary to generate the event log as defined by Trusted Computing Group (TCG); the digest size, to pad/truncate a digest calculated with a different algorithm; the crypto subsystem identifier, to calculate the digest of event data. This patch also protects against data corruption that could happen in the bus, by checking that the digest size returned by the TPM during a PCR read matches the size of the algorithm passed to tpm2_pcr_read(). For the initial PCR read, when digest sizes are not yet available, this patch ensures that the amount of data copied from the output returned by the TPM does not exceed the size of the array data are copied to. Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
2019-02-06 16:24:49 +00:00
chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg;
rc = tpm2_init_bank_info(chip, nr_alloc_banks);
if (rc < 0)
break;
nr_alloc_banks++;
}
sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) +
sizeof(pcr_selection.size_of_select) +
pcr_selection.size_of_select;
marker = marker + sizeof_pcr_selection;
}
chip->nr_allocated_banks = nr_alloc_banks;
out:
tpm_buf_destroy(&buf);
return rc;
}
int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
{
struct tpm_buf buf;
u32 nr_commands;
__be32 *attrs;
u32 cc;
int i;
int rc;
rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
if (rc)
goto out;
if (nr_commands > 0xFFFFF) {
rc = -EFAULT;
goto out;
}
treewide: devm_kzalloc() -> devm_kcalloc() The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc(). This patch replaces cases of: devm_kzalloc(handle, a * b, gfp) with: devm_kcalloc(handle, a * b, gfp) as well as handling cases of: devm_kzalloc(handle, a * b * c, gfp) with: devm_kzalloc(handle, array3_size(a, b, c), gfp) as it's slightly less ugly than: devm_kcalloc(handle, array_size(a, b), c, gfp) This does, however, attempt to ignore constant size factors like: devm_kzalloc(handle, 4 * 1024, gfp) though any constants defined via macros get caught up in the conversion. Any factors with a sizeof() of "unsigned char", "char", and "u8" were dropped, since they're redundant. Some manual whitespace fixes were needed in this patch, as Coccinelle really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...". The Coccinelle script used for this was: // Fix redundant parens around sizeof(). @@ expression HANDLE; type TYPE; expression THING, E; @@ ( devm_kzalloc(HANDLE, - (sizeof(TYPE)) * E + sizeof(TYPE) * E , ...) | devm_kzalloc(HANDLE, - (sizeof(THING)) * E + sizeof(THING) * E , ...) ) // Drop single-byte sizes and redundant parens. @@ expression HANDLE; expression COUNT; typedef u8; typedef __u8; @@ ( devm_kzalloc(HANDLE, - sizeof(u8) * (COUNT) + COUNT , ...) | devm_kzalloc(HANDLE, - sizeof(__u8) * (COUNT) + COUNT , ...) | devm_kzalloc(HANDLE, - sizeof(char) * (COUNT) + COUNT , ...) | devm_kzalloc(HANDLE, - sizeof(unsigned char) * (COUNT) + COUNT , ...) | devm_kzalloc(HANDLE, - sizeof(u8) * COUNT + COUNT , ...) | devm_kzalloc(HANDLE, - sizeof(__u8) * COUNT + COUNT , ...) | devm_kzalloc(HANDLE, - sizeof(char) * COUNT + COUNT , ...) | devm_kzalloc(HANDLE, - sizeof(unsigned char) * COUNT + COUNT , ...) ) // 2-factor product with sizeof(type/expression) and identifier or constant. @@ expression HANDLE; type TYPE; expression THING; identifier COUNT_ID; constant COUNT_CONST; @@ ( - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(TYPE) * (COUNT_ID) + COUNT_ID, sizeof(TYPE) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(TYPE) * COUNT_ID + COUNT_ID, sizeof(TYPE) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(TYPE) * (COUNT_CONST) + COUNT_CONST, sizeof(TYPE) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(TYPE) * COUNT_CONST + COUNT_CONST, sizeof(TYPE) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(THING) * (COUNT_ID) + COUNT_ID, sizeof(THING) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(THING) * COUNT_ID + COUNT_ID, sizeof(THING) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(THING) * (COUNT_CONST) + COUNT_CONST, sizeof(THING) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(THING) * COUNT_CONST + COUNT_CONST, sizeof(THING) , ...) ) // 2-factor product, only identifiers. @@ expression HANDLE; identifier SIZE, COUNT; @@ - devm_kzalloc + devm_kcalloc (HANDLE, - SIZE * COUNT + COUNT, SIZE , ...) // 3-factor product with 1 sizeof(type) or sizeof(expression), with // redundant parens removed. @@ expression HANDLE; expression THING; identifier STRIDE, COUNT; type TYPE; @@ ( devm_kzalloc(HANDLE, - sizeof(TYPE) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | devm_kzalloc(HANDLE, - sizeof(TYPE) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | devm_kzalloc(HANDLE, - sizeof(TYPE) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | devm_kzalloc(HANDLE, - sizeof(TYPE) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(TYPE)) , ...) | devm_kzalloc(HANDLE, - sizeof(THING) * (COUNT) * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | devm_kzalloc(HANDLE, - sizeof(THING) * (COUNT) * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | devm_kzalloc(HANDLE, - sizeof(THING) * COUNT * (STRIDE) + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) | devm_kzalloc(HANDLE, - sizeof(THING) * COUNT * STRIDE + array3_size(COUNT, STRIDE, sizeof(THING)) , ...) ) // 3-factor product with 2 sizeof(variable), with redundant parens removed. @@ expression HANDLE; expression THING1, THING2; identifier COUNT; type TYPE1, TYPE2; @@ ( devm_kzalloc(HANDLE, - sizeof(TYPE1) * sizeof(TYPE2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | devm_kzalloc(HANDLE, - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2)) , ...) | devm_kzalloc(HANDLE, - sizeof(THING1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | devm_kzalloc(HANDLE, - sizeof(THING1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(THING1), sizeof(THING2)) , ...) | devm_kzalloc(HANDLE, - sizeof(TYPE1) * sizeof(THING2) * COUNT + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) | devm_kzalloc(HANDLE, - sizeof(TYPE1) * sizeof(THING2) * (COUNT) + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2)) , ...) ) // 3-factor product, only identifiers, with redundant parens removed. @@ expression HANDLE; identifier STRIDE, SIZE, COUNT; @@ ( devm_kzalloc(HANDLE, - (COUNT) * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | devm_kzalloc(HANDLE, - COUNT * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | devm_kzalloc(HANDLE, - COUNT * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | devm_kzalloc(HANDLE, - (COUNT) * (STRIDE) * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) | devm_kzalloc(HANDLE, - COUNT * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | devm_kzalloc(HANDLE, - (COUNT) * STRIDE * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | devm_kzalloc(HANDLE, - (COUNT) * (STRIDE) * (SIZE) + array3_size(COUNT, STRIDE, SIZE) , ...) | devm_kzalloc(HANDLE, - COUNT * STRIDE * SIZE + array3_size(COUNT, STRIDE, SIZE) , ...) ) // Any remaining multi-factor products, first at least 3-factor products, // when they're not all constants... @@ expression HANDLE; expression E1, E2, E3; constant C1, C2, C3; @@ ( devm_kzalloc(HANDLE, C1 * C2 * C3, ...) | devm_kzalloc(HANDLE, - (E1) * E2 * E3 + array3_size(E1, E2, E3) , ...) | devm_kzalloc(HANDLE, - (E1) * (E2) * E3 + array3_size(E1, E2, E3) , ...) | devm_kzalloc(HANDLE, - (E1) * (E2) * (E3) + array3_size(E1, E2, E3) , ...) | devm_kzalloc(HANDLE, - E1 * E2 * E3 + array3_size(E1, E2, E3) , ...) ) // And then all remaining 2 factors products when they're not all constants, // keeping sizeof() as the second factor argument. @@ expression HANDLE; expression THING, E1, E2; type TYPE; constant C1, C2, C3; @@ ( devm_kzalloc(HANDLE, sizeof(THING) * C2, ...) | devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...) | devm_kzalloc(HANDLE, C1 * C2 * C3, ...) | devm_kzalloc(HANDLE, C1 * C2, ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(TYPE) * (E2) + E2, sizeof(TYPE) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(TYPE) * E2 + E2, sizeof(TYPE) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(THING) * (E2) + E2, sizeof(THING) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - sizeof(THING) * E2 + E2, sizeof(THING) , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - (E1) * E2 + E1, E2 , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - (E1) * (E2) + E1, E2 , ...) | - devm_kzalloc + devm_kcalloc (HANDLE, - E1 * E2 + E1, E2 , ...) ) Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 21:07:58 +00:00
chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands,
GFP_KERNEL);
if (!chip->cc_attrs_tbl) {
rc = -ENOMEM;
goto out;
}
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
if (rc)
goto out;
tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
tpm_buf_append_u32(&buf, nr_commands);
rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
if (rc) {
tpm_buf_destroy(&buf);
goto out;
}
if (nr_commands !=
be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
rc = -EFAULT;
tpm_buf_destroy(&buf);
goto out;
}
chip->nr_commands = nr_commands;
attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9];
for (i = 0; i < nr_commands; i++, attrs++) {
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
cc = chip->cc_attrs_tbl[i] & 0xFFFF;
if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) {
chip->cc_attrs_tbl[i] &=
~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES);
chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES;
}
}
tpm_buf_destroy(&buf);
out:
if (rc > 0)
rc = -ENODEV;
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl);
/**
* tpm2_startup - turn on the TPM
* @chip: TPM chip to use
*
* Normally the firmware should start the TPM. This function is provided as a
* workaround if this does not happen. A legal case for this could be for
* example when a TPM emulator is used.
*
* Return: same as tpm_transmit_cmd()
*/
static int tpm2_startup(struct tpm_chip *chip)
{
struct tpm_buf buf;
int rc;
dev_info(&chip->dev, "starting up the TPM manually\n");
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
if (rc < 0)
return rc;
tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
tpm_buf_destroy(&buf);
return rc;
}
/**
* tpm2_auto_startup - Perform the standard automatic TPM initialization
* sequence
* @chip: TPM chip to use
*
* Returns 0 on success, < 0 in case of fatal error.
*/
int tpm2_auto_startup(struct tpm_chip *chip)
{
int rc;
rc = tpm2_get_timeouts(chip);
if (rc)
goto out;
rc = tpm2_do_selftest(chip);
tpm: fix intermittent failure with self tests My Nuvoton 6xx in a Dell XPS-13 has been intermittently failing to work (necessitating a reboot). The problem seems to be that the TPM gets into a state where the partial self-test doesn't return TPM_RC_SUCCESS (meaning all tests have run to completion), but instead returns TPM_RC_TESTING (meaning some tests are still running in the background). There are various theories that resending the self-test command actually causes the tests to restart and thus triggers more TPM_RC_TESTING returns until the timeout is exceeded. There are several issues here: firstly being we shouldn't slow down the boot sequence waiting for the self test to complete once the TPM backgrounds them. It will actually make available all functions that have passed and if it gets a failure return TPM_RC_FAILURE to every subsequent command. So the fix is to kick off self tests once and if they return TPM_RC_TESTING log that as a backgrounded self test and continue on. In order to prevent other tpm users from seeing any TPM_RC_TESTING returns (which it might if they send a command that needs a TPM subsystem which is still under test), we loop in tpm_transmit_cmd until either a timeout or we don't get a TPM_RC_TESTING return. Finally, there have been observations of strange returns from a partial test. One Nuvoton is occasionally returning TPM_RC_COMMAND_CODE, so treat any unexpected return from a partial self test as an indication we need to run a full self test. [jarkko.sakkinen@linux.intel.com: cleaned up some klog messages and dropped tpm_transmit_check() helper function from James' original commit.] Fixes: 2482b1bba5122 ("tpm: Trigger only missing TPM 2.0 self tests") Cc: stable@vger.kernel.org Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com>
2018-03-22 15:32:20 +00:00
if (rc && rc != TPM2_RC_INITIALIZE)
goto out;
if (rc == TPM2_RC_INITIALIZE) {
rc = tpm2_startup(chip);
if (rc)
goto out;
rc = tpm2_do_selftest(chip);
tpm: fix intermittent failure with self tests My Nuvoton 6xx in a Dell XPS-13 has been intermittently failing to work (necessitating a reboot). The problem seems to be that the TPM gets into a state where the partial self-test doesn't return TPM_RC_SUCCESS (meaning all tests have run to completion), but instead returns TPM_RC_TESTING (meaning some tests are still running in the background). There are various theories that resending the self-test command actually causes the tests to restart and thus triggers more TPM_RC_TESTING returns until the timeout is exceeded. There are several issues here: firstly being we shouldn't slow down the boot sequence waiting for the self test to complete once the TPM backgrounds them. It will actually make available all functions that have passed and if it gets a failure return TPM_RC_FAILURE to every subsequent command. So the fix is to kick off self tests once and if they return TPM_RC_TESTING log that as a backgrounded self test and continue on. In order to prevent other tpm users from seeing any TPM_RC_TESTING returns (which it might if they send a command that needs a TPM subsystem which is still under test), we loop in tpm_transmit_cmd until either a timeout or we don't get a TPM_RC_TESTING return. Finally, there have been observations of strange returns from a partial test. One Nuvoton is occasionally returning TPM_RC_COMMAND_CODE, so treat any unexpected return from a partial self test as an indication we need to run a full self test. [jarkko.sakkinen@linux.intel.com: cleaned up some klog messages and dropped tpm_transmit_check() helper function from James' original commit.] Fixes: 2482b1bba5122 ("tpm: Trigger only missing TPM 2.0 self tests") Cc: stable@vger.kernel.org Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkine@linux.intel.com>
2018-03-22 15:32:20 +00:00
if (rc)
goto out;
}
rc = tpm2_get_cc_attrs_tbl(chip);
if (rc == TPM2_RC_FAILURE || (rc < 0 && rc != -ENOMEM)) {
dev_info(&chip->dev,
"TPM in field failure mode, requires firmware upgrade\n");
chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE;
rc = 0;
}
out:
/*
* Infineon TPM in field upgrade mode will return no data for the number
* of supported commands.
*/
if (rc == TPM2_RC_UPGRADE || rc == -ENODATA) {
tpm: Add Upgrade/Reduced mode support for TPM2 modules If something went wrong during the TPM firmware upgrade, like power failure or the firmware image file get corrupted, the TPM might end up in Upgrade or Failure mode upon the next start. The state is persistent between the TPM power cycle/restart. According to TPM specification: * If the TPM is in Upgrade mode, it will answer with TPM2_RC_UPGRADE to all commands except TPM2_FieldUpgradeData(). It may also accept other commands if it is able to complete them using the previously installed firmware. * If the TPM is in Failure mode, it will allow performing TPM initialization but will not provide any crypto operations. Will happily respond to Field Upgrade calls. Change the behavior of the tpm2_auto_startup(), so it detects the active running mode of the TPM by adding the following checks. If tpm2_do_selftest() call returns TPM2_RC_UPGRADE, the TPM is in Upgrade mode. If the TPM is in Failure mode, it will successfully respond to both tpm2_do_selftest() and tpm2_startup() calls. Although, will fail to answer to tpm2_get_cc_attrs_tbl(). Use this fact to conclude that TPM is in Failure mode. If detected that the TPM is in the Upgrade or Failure mode, the function sets TPM_CHIP_FLAG_FIRMWARE_UPGRADE_MODE flag. The TPM_CHIP_FLAG_FIRMWARE_UPGRADE_MODE flag is used later during driver initialization/deinitialization to disable functionality which makes no sense or will fail in the current TPM state. Following functionality is affected: * Do not register TPM as a hwrng * Do not register sysfs entries which provide information impossible to obtain in limited mode * Do not register resource managed character device Signed-off-by: axelj <axelj@axis.com> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
2021-12-13 07:09:25 +00:00
dev_info(&chip->dev, "TPM in field upgrade mode, requires firmware upgrade\n");
chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE;
rc = 0;
}
if (rc > 0)
rc = -ENODEV;
return rc;
}
int tpm2_find_cc(struct tpm_chip *chip, u32 cc)
{
int i;
for (i = 0; i < chip->nr_commands; i++)
if (cc == (chip->cc_attrs_tbl[i] & GENMASK(15, 0)))
return i;
return -1;
}