[PATCH v6 07/11] tpm: Send only one at most TPM2_GetRandom command

Jarkko Sakkinen posted 11 patches 1 day, 15 hours ago
[PATCH v6 07/11] tpm: Send only one at most TPM2_GetRandom command
Posted by Jarkko Sakkinen 1 day, 15 hours ago
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 <davem@davemloft.net>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
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