hwrng framework does not have a requirement that the all bytes requested need to be provided. By enforcing such a requirement internally, TPM driver can cause unpredictability in latency, as a single tpm_get_random() call can result multiple TPM commands.
Especially, when TCG_TPM2_HMAC is enabled, extra roundtrips could have significant effect to the system latency. Add a wait-parameter to enforce the old behavior and set it to true only at the call sites for TPM 1.2 keys. At the call sites of hwrng, set @wait to false. Cc: David S. Miller <[email protected]> Cc: Herbert Xu <[email protected]> Signed-off-by: Jarkko Sakkinen <[email protected]> --- v4: - Fixed grammar mistakes. --- drivers/char/tpm/tpm-chip.c | 2 +- drivers/char/tpm/tpm-interface.c | 11 +++++++++-- include/linux/tpm.h | 2 +- security/keys/trusted-keys/trusted_tpm1.c | 8 ++++---- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 082b910ddf0d..8fca4373e2df 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -494,7 +494,7 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) { struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); - return tpm_get_random(chip, data, max); + return tpm_get_random(chip, data, max, false); } static bool tpm_is_hwrng_enabled(struct tpm_chip *chip) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index d157be738612..0a79ed3696b7 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -614,9 +614,11 @@ static int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) * @chip: A &tpm_chip instance. Whenset to %NULL, the default chip is used. * @out: Destination buffer for the acquired random bytes. * @max: The maximum number of bytes to write to @out. + * @wait: Set to true when all of the @max bytes need to be acquired. * * Iterates pulling more bytes from TPM up until all of the @max bytes have been - * received. + * received, when @wait it sets true. Otherwise, the queries for @max bytes from + * TPM exactly once, and returns the bytes that were received. * * Returns the number of random bytes read on success. * Returns -EINVAL when @out is NULL, or @max is not between zero and @@ -624,7 +626,7 @@ static int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) * Returns tpm_transmit_cmd() error codes when the TPM command results an * error. */ -int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) +int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max, bool wait) { u32 num_bytes = max; u8 *out_ptr = out; @@ -657,6 +659,11 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) if (rc < 0) goto err; + if (!wait) { + total = rc; + break; + } + out_ptr += rc; total += rc; num_bytes -= rc; diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 72610f1aa402..d710a3aea2ff 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -487,7 +487,7 @@ extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, struct tpm_digest *digest); extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, struct tpm_digest *digests); -extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); +int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max, bool wait); extern struct tpm_chip *tpm_default_chip(void); void tpm2_flush_context(struct tpm_chip *chip, u32 handle); int tpm2_find_hash_alg(unsigned int crypto_id); diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c index 636acb66a4f6..5b5f7a029bc3 100644 --- a/security/keys/trusted-keys/trusted_tpm1.c +++ b/security/keys/trusted-keys/trusted_tpm1.c @@ -361,7 +361,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, unsigned char ononce[TPM_NONCE_SIZE]; int ret; - ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE, true); if (ret < 0) return ret; @@ -454,7 +454,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE); sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash); - ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE, true); if (ret < 0) goto out; @@ -565,7 +565,7 @@ static int tpm_unseal(struct tpm_buf *tb, } ordinal = htonl(TPM_ORD_UNSEAL); - ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE); + ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE, true); if (ret < 0) return ret; @@ -938,7 +938,7 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob) static int trusted_tpm_get_random(unsigned char *key, size_t key_len) { - return tpm_get_random(chip, key, key_len); + return tpm_get_random(chip, key, key_len, true); } static int __init init_digests(void) -- 2.39.5
