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 ab52a1cb0a78..5cc2bbabd57a 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -604,9 +604,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
@@ -614,7 +616,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;
@@ -647,6 +649,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 e68995df8796..177833d6b965 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -485,7 +485,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 759c1ecb0435..f36f6a0b533f 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


Reply via email to