Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 3acf4fd..ba9acae 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014, 2015 Intel Corporation
*
@@ -8,11 +9,6 @@
*
* This file contains TPM2 protocol implementations of the commands
* used by the kernel internally.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
*/
#include "tpm.h"
@@ -33,136 +29,128 @@
};
static struct tpm2_hash tpm2_hash_map[] = {
- {HASH_ALGO_SHA1, TPM2_ALG_SHA1},
- {HASH_ALGO_SHA256, TPM2_ALG_SHA256},
- {HASH_ALGO_SHA384, TPM2_ALG_SHA384},
- {HASH_ALGO_SHA512, TPM2_ALG_SHA512},
- {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
+ {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},
};
-/*
- * Array with one entry per ordinal defining the maximum amount
- * of time the chip could take to return the result. The values
- * of the SHORT, MEDIUM, and LONG durations are taken from the
- * PC Client Profile (PTP) specification.
- * LONG_LONG is for commands that generates keys which empirically
- * takes longer time on some systems.
+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 const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
- TPM_UNDEFINED, /* 11F */
- TPM_UNDEFINED, /* 120 */
- TPM_LONG, /* 121 */
- TPM_UNDEFINED, /* 122 */
- TPM_UNDEFINED, /* 123 */
- TPM_UNDEFINED, /* 124 */
- TPM_UNDEFINED, /* 125 */
- TPM_UNDEFINED, /* 126 */
- TPM_UNDEFINED, /* 127 */
- TPM_UNDEFINED, /* 128 */
- TPM_LONG, /* 129 */
- TPM_UNDEFINED, /* 12a */
- TPM_UNDEFINED, /* 12b */
- TPM_UNDEFINED, /* 12c */
- TPM_UNDEFINED, /* 12d */
- TPM_UNDEFINED, /* 12e */
- TPM_UNDEFINED, /* 12f */
- TPM_UNDEFINED, /* 130 */
- TPM_LONG_LONG, /* 131 */
- TPM_UNDEFINED, /* 132 */
- TPM_UNDEFINED, /* 133 */
- TPM_UNDEFINED, /* 134 */
- TPM_UNDEFINED, /* 135 */
- TPM_UNDEFINED, /* 136 */
- TPM_UNDEFINED, /* 137 */
- TPM_UNDEFINED, /* 138 */
- TPM_UNDEFINED, /* 139 */
- TPM_UNDEFINED, /* 13a */
- TPM_UNDEFINED, /* 13b */
- TPM_UNDEFINED, /* 13c */
- TPM_UNDEFINED, /* 13d */
- TPM_MEDIUM, /* 13e */
- TPM_UNDEFINED, /* 13f */
- TPM_UNDEFINED, /* 140 */
- TPM_UNDEFINED, /* 141 */
- TPM_UNDEFINED, /* 142 */
- TPM_LONG, /* 143 */
- TPM_MEDIUM, /* 144 */
- TPM_UNDEFINED, /* 145 */
- TPM_UNDEFINED, /* 146 */
- TPM_UNDEFINED, /* 147 */
- TPM_UNDEFINED, /* 148 */
- TPM_UNDEFINED, /* 149 */
- TPM_UNDEFINED, /* 14a */
- TPM_UNDEFINED, /* 14b */
- TPM_UNDEFINED, /* 14c */
- TPM_UNDEFINED, /* 14d */
- TPM_LONG, /* 14e */
- TPM_UNDEFINED, /* 14f */
- TPM_UNDEFINED, /* 150 */
- TPM_UNDEFINED, /* 151 */
- TPM_UNDEFINED, /* 152 */
- TPM_LONG_LONG, /* 153 */
- TPM_UNDEFINED, /* 154 */
- TPM_UNDEFINED, /* 155 */
- TPM_UNDEFINED, /* 156 */
- TPM_UNDEFINED, /* 157 */
- TPM_UNDEFINED, /* 158 */
- TPM_UNDEFINED, /* 159 */
- TPM_UNDEFINED, /* 15a */
- TPM_UNDEFINED, /* 15b */
- TPM_MEDIUM, /* 15c */
- TPM_UNDEFINED, /* 15d */
- TPM_UNDEFINED, /* 15e */
- TPM_UNDEFINED, /* 15f */
- TPM_UNDEFINED, /* 160 */
- TPM_UNDEFINED, /* 161 */
- TPM_UNDEFINED, /* 162 */
- TPM_UNDEFINED, /* 163 */
- TPM_UNDEFINED, /* 164 */
- TPM_UNDEFINED, /* 165 */
- TPM_UNDEFINED, /* 166 */
- TPM_UNDEFINED, /* 167 */
- TPM_UNDEFINED, /* 168 */
- TPM_UNDEFINED, /* 169 */
- TPM_UNDEFINED, /* 16a */
- TPM_UNDEFINED, /* 16b */
- TPM_UNDEFINED, /* 16c */
- TPM_UNDEFINED, /* 16d */
- TPM_UNDEFINED, /* 16e */
- TPM_UNDEFINED, /* 16f */
- TPM_UNDEFINED, /* 170 */
- TPM_UNDEFINED, /* 171 */
- TPM_UNDEFINED, /* 172 */
- TPM_UNDEFINED, /* 173 */
- TPM_UNDEFINED, /* 174 */
- TPM_UNDEFINED, /* 175 */
- TPM_UNDEFINED, /* 176 */
- TPM_LONG, /* 177 */
- TPM_UNDEFINED, /* 178 */
- TPM_UNDEFINED, /* 179 */
- TPM_MEDIUM, /* 17a */
- TPM_LONG, /* 17b */
- TPM_UNDEFINED, /* 17c */
- TPM_UNDEFINED, /* 17d */
- TPM_UNDEFINED, /* 17e */
- TPM_UNDEFINED, /* 17f */
- TPM_UNDEFINED, /* 180 */
- TPM_UNDEFINED, /* 181 */
- TPM_MEDIUM, /* 182 */
- TPM_UNDEFINED, /* 183 */
- TPM_UNDEFINED, /* 184 */
- TPM_MEDIUM, /* 185 */
- TPM_MEDIUM, /* 186 */
- TPM_UNDEFINED, /* 187 */
- TPM_UNDEFINED, /* 188 */
- TPM_UNDEFINED, /* 189 */
- TPM_UNDEFINED, /* 18a */
- TPM_UNDEFINED, /* 18b */
- TPM_UNDEFINED, /* 18c */
- TPM_UNDEFINED, /* 18d */
- TPM_UNDEFINED, /* 18e */
- TPM_UNDEFINED /* 18f */
-};
+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;
+
+ 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;
@@ -179,20 +167,36 @@
* tpm2_pcr_read() - read a PCR value
* @chip: TPM chip to use.
* @pcr_idx: index of the PCR to read.
- * @res_buf: buffer to store the resulting hash.
+ * @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.
*/
-int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
+int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
+ struct tpm_digest *digest, u16 *digest_size_ptr)
{
+ int i;
int rc;
struct tpm_buf buf;
struct tpm2_pcr_read_out *out;
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
+ u16 digest_size;
+ u16 expected_digest_size = 0;
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
+ 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;
@@ -200,18 +204,28 @@
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
tpm_buf_append_u32(&buf, 1);
- tpm_buf_append_u16(&buf, TPM2_ALG_SHA1);
+ 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));
- rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
- res_buf ? "attempting to read a pcr value" : NULL);
- if (rc == 0 && res_buf) {
- out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
- memcpy(res_buf, out->digest, SHA1_DIGEST_SIZE);
+ 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;
}
+ if (digest_size_ptr)
+ *digest_size_ptr = digest_size;
+
+ memcpy(digest->digest, out->digest, digest_size);
+out:
tpm_buf_destroy(&buf);
return rc;
}
@@ -228,22 +242,17 @@
*
* @chip: TPM chip to use.
* @pcr_idx: index of the PCR.
- * @count: number of digests passed.
* @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, int pcr_idx, u32 count,
- struct tpm2_digest *digests)
+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;
- int j;
-
- if (count > ARRAY_SIZE(chip->active_banks))
- return -EINVAL;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
if (rc)
@@ -259,28 +268,21 @@
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, count);
+ tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
- for (i = 0; i < count; i++) {
- for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) {
- if (digests[i].alg_id != tpm2_hash_map[j].tpm_id)
- continue;
- tpm_buf_append_u16(&buf, digests[i].alg_id);
- tpm_buf_append(&buf, (const unsigned char
- *)&digests[i].digest,
- hash_digest_size[tpm2_hash_map[j].crypto_id]);
- }
+ for (i = 0; i < chip->nr_allocated_banks; i++) {
+ 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, NULL, buf.data, PAGE_SIZE, 0, 0,
- "attempting extend a PCR value");
+ 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];
@@ -295,7 +297,7 @@
*
* Return:
* size of the buffer on success,
- * -errno otherwise
+ * -errno otherwise (positive TPM return codes are masked to -EIO)
*/
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
@@ -318,12 +320,15 @@
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, NULL, buf.data, PAGE_SIZE,
+ err = tpm_transmit_cmd(chip, &buf,
offsetof(struct tpm2_get_random_out,
buffer),
- 0, "attempting get random");
- if (err)
+ "attempting get random");
+ if (err) {
+ if (err > 0)
+ err = -EIO;
goto out;
+ }
out = (struct tpm2_get_random_out *)
&buf.data[TPM_HEADER_SIZE];
@@ -350,15 +355,11 @@
}
/**
- * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
- * @chip: TPM chip to use
- * @payload: the key data in clear and encrypted form
- * @options: authentication values and other options
- *
- * Return: same as with tpm_transmit_cmd
+ * tpm2_flush_context() - execute a TPM2_FlushContext command
+ * @chip: TPM chip to use
+ * @handle: context handle
*/
-void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
- unsigned int flags)
+void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
struct tpm_buf buf;
int rc;
@@ -372,9 +373,7 @@
tpm_buf_append_u32(&buf, handle);
- (void) tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, flags,
- "flushing context");
-
+ tpm_transmit_cmd(chip, &buf, 0, "flushing context");
tpm_buf_destroy(&buf);
}
@@ -459,7 +458,7 @@
/* public */
tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
- tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
+ tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH);
tpm_buf_append_u16(&buf, hash);
/* policy */
@@ -474,7 +473,7 @@
}
/* public parameters */
- tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
+ tpm_buf_append_u16(&buf, TPM_ALG_NULL);
tpm_buf_append_u16(&buf, 0);
/* outside info */
@@ -488,8 +487,7 @@
goto out;
}
- rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0,
- "sealing data");
+ rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
if (rc)
goto out;
@@ -526,7 +524,6 @@
* @payload: the key data in clear and encrypted form
* @options: authentication values and other options
* @blob_handle: returned blob handle
- * @flags: tpm transmit flags
*
* Return: 0 on success.
* -E2BIG on wrong payload size.
@@ -536,7 +533,7 @@
static int tpm2_load_cmd(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options,
- u32 *blob_handle, unsigned int flags)
+ u32 *blob_handle)
{
struct tpm_buf buf;
unsigned int private_len;
@@ -571,8 +568,7 @@
goto out;
}
- rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags,
- "loading blob");
+ rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
if (!rc)
*blob_handle = be32_to_cpup(
(__be32 *) &buf.data[TPM_HEADER_SIZE]);
@@ -593,7 +589,6 @@
* @payload: the key data in clear and encrypted form
* @options: authentication values and other options
* @blob_handle: blob handle
- * @flags: tpm_transmit_cmd flags
*
* Return: 0 on success
* -EPERM on tpm error status
@@ -602,7 +597,7 @@
static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options,
- u32 blob_handle, unsigned int flags)
+ u32 blob_handle)
{
struct tpm_buf buf;
u16 data_len;
@@ -622,8 +617,7 @@
options->blobauth /* hmac */,
TPM_DIGEST_SIZE);
- rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags,
- "unsealing");
+ rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
if (rc > 0)
rc = -EPERM;
@@ -667,17 +661,12 @@
u32 blob_handle;
int rc;
- mutex_lock(&chip->tpm_mutex);
- rc = tpm2_load_cmd(chip, payload, options, &blob_handle,
- TPM_TRANSMIT_UNLOCKED);
+ rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
if (rc)
- goto out;
+ return rc;
- rc = tpm2_unseal_cmd(chip, payload, options, blob_handle,
- TPM_TRANSMIT_UNLOCKED);
- tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED);
-out:
- mutex_unlock(&chip->tpm_mutex);
+ rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
+ tpm2_flush_context(chip, blob_handle);
return rc;
}
@@ -713,7 +702,7 @@
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, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
+ rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
if (!rc) {
out = (struct tpm2_get_cap_out *)
&buf.data[TPM_HEADER_SIZE];
@@ -743,37 +732,10 @@
if (rc)
return;
tpm_buf_append_u16(&buf, shutdown_type);
- tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
- "stopping the TPM");
+ tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
tpm_buf_destroy(&buf);
}
-/*
- * tpm2_calc_ordinal_duration() - maximum duration for a command
- *
- * @chip: TPM chip to use.
- * @ordinal: command code number.
- *
- * Return: maximum duration for a command
- */
-unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
-{
- int index = TPM_UNDEFINED;
- int duration = 0;
-
- if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST)
- index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST];
-
- if (index != TPM_UNDEFINED)
- duration = chip->duration[index];
-
- if (duration <= 0)
- duration = msecs_to_jiffies(TPM2_DURATION_DEFAULT);
-
- return duration;
-}
-EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
-
/**
* tpm2_do_selftest() - ensure that all self tests have passed
*
@@ -799,7 +761,7 @@
return rc;
tpm_buf_append_u8(&buf, full);
- rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
+ rc = tpm_transmit_cmd(chip, &buf, 0,
"attempting the self test");
tpm_buf_destroy(&buf);
@@ -826,7 +788,7 @@
*/
int tpm2_probe(struct tpm_chip *chip)
{
- struct tpm_output_header *out;
+ struct tpm_header *out;
struct tpm_buf buf;
int rc;
@@ -836,10 +798,10 @@
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, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
+ rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
/* We ignore TPM return codes on purpose. */
if (rc >= 0) {
- out = (struct tpm_output_header *)buf.data;
+ out = (struct tpm_header *)buf.data;
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
}
@@ -848,21 +810,47 @@
}
EXPORT_SYMBOL_GPL(tpm2_probe);
+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;
+ }
+
+ 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;
-static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
+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;
- unsigned int count;
u32 sizeof_pcr_selection;
+ u32 nr_possible_banks;
+ u32 nr_alloc_banks = 0;
+ u16 hash_alg;
u32 rsp_len;
int rc;
int i = 0;
@@ -875,16 +863,18 @@
tpm_buf_append_u32(&buf, 0);
tpm_buf_append_u32(&buf, 1);
- rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 9, 0,
- "get tpm pcr allocation");
+ rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
if (rc)
goto out;
- count = be32_to_cpup(
+ nr_possible_banks = be32_to_cpup(
(__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
- if (count > ARRAY_SIZE(chip->active_banks)) {
- rc = -ENODEV;
+ chip->allocated_banks = kcalloc(nr_possible_banks,
+ sizeof(*chip->allocated_banks),
+ GFP_KERNEL);
+ if (!chip->allocated_banks) {
+ rc = -ENOMEM;
goto out;
}
@@ -893,7 +883,7 @@
rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
end = &buf.data[rsp_len];
- for (i = 0; i < count; i++) {
+ 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) {
@@ -902,17 +892,28 @@
}
memcpy(&pcr_selection, marker, sizeof(pcr_selection));
- chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg);
+ 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) {
+ 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:
- if (i < ARRAY_SIZE(chip->active_banks))
- chip->active_banks[i] = TPM2_ALG_ERROR;
-
tpm_buf_destroy(&buf);
return rc;
@@ -947,8 +948,7 @@
tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
tpm_buf_append_u32(&buf, nr_commands);
- rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
- 9 + 4 * nr_commands, 0, NULL);
+ rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
if (rc) {
tpm_buf_destroy(&buf);
goto out;
@@ -983,6 +983,35 @@
}
/**
+ * 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
@@ -993,7 +1022,7 @@
{
int rc;
- rc = tpm_get_timeouts(chip);
+ rc = tpm2_get_timeouts(chip);
if (rc)
goto out;
@@ -1002,7 +1031,7 @@
goto out;
if (rc == TPM2_RC_INITIALIZE) {
- rc = tpm_startup(chip);
+ rc = tpm2_startup(chip);
if (rc)
goto out;
@@ -1011,10 +1040,6 @@
goto out;
}
- rc = tpm2_get_pcr_allocation(chip);
- if (rc)
- goto out;
-
rc = tpm2_get_cc_attrs_tbl(chip);
out: