From: Jarkko Sakkinen <jarkko@kernel.org>
To: linux-integrity@vger.kernel.org
Cc: Jarkko Sakkinen <jarkko@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Herbert Xu <herbert@gondor.apana.org.au>,
Eric Biggers <ebiggers@kernel.org>,
James Bottomley <James.Bottomley@HansenPartnership.com>,
Mimi Zohar <zohar@linux.ibm.com>,
David Howells <dhowells@redhat.com>,
Paul Moore <paul@paul-moore.com>,
James Morris <jmorris@namei.org>,
"Serge E. Hallyn" <serge@hallyn.com>,
keyrings@vger.kernel.org (open list:KEYS-TRUSTED),
linux-security-module@vger.kernel.org (open list:SECURITY
SUBSYSTEM), linux-kernel@vger.kernel.org (open list)
Subject: [PATCH v9 03/11] tpm: Change tpm_get_random() opportunistic
Date: Sun, 25 Jan 2026 21:25:13 +0200 [thread overview]
Message-ID: <20260125192526.782202-4-jarkko@kernel.org> (raw)
In-Reply-To: <20260125192526.782202-1-jarkko@kernel.org>
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.
Thus, send TPM command only once and return bytes received instead of
committing to the number of requested bytes.
Cc: David S. Miller <davem@davemloft.net>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
v9:
- Merge orchestration.
v7:
- Given that hwrng is now only caller for tpm_get_random(), remove the
wait parameter.
v4:
- Fixed grammar mistakes.
---
drivers/char/tpm/tpm-interface.c | 20 ++++--
drivers/char/tpm/tpm1-cmd.c | 66 ++++++++----------
drivers/char/tpm/tpm2-cmd.c | 115 +++++++++++++------------------
3 files changed, 88 insertions(+), 113 deletions(-)
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index f745a098908b..d44bd8c44612 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -487,18 +487,24 @@ int tpm_pm_resume(struct device *dev)
EXPORT_SYMBOL_GPL(tpm_pm_resume);
/**
- * tpm_get_random() - get random bytes from the TPM's RNG
- * @chip: a &struct tpm_chip instance, %NULL for the default chip
- * @out: destination buffer for the random bytes
- * @max: the max number of bytes to write to @out
+ * tpm_get_random() - Get random bytes from the TPM's RNG
+ * @chip: A &tpm_chip instance. When set 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.
+ *
+ * Tries to pull bytes from the TPM. At most, @max bytes are returned.
*
- * Return: number of random bytes read or a negative error value.
+ * Returns the number of random bytes read on success.
+ * Returns -EINVAL when @out is NULL, or @max is not between zero and
+ * %TPM_MAX_RNG_DATA.
+ * 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 rc;
- if (!out || max > TPM_MAX_RNG_DATA)
+ if (!out || !max || max > TPM_MAX_RNG_DATA)
return -EINVAL;
if (!chip)
@@ -514,7 +520,7 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
rc = tpm1_get_random(chip, out, max);
tpm_put_ops(chip);
- return rc;
+ return rc != 0 ? rc : -EIO;
}
EXPORT_SYMBOL_GPL(tpm_get_random);
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index b49a790f1bd5..3fe94f596f97 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -518,63 +518,51 @@ struct tpm1_get_random_out {
} __packed;
/**
- * tpm1_get_random() - get random bytes from the TPM's RNG
- * @chip: a &struct tpm_chip instance
- * @dest: destination buffer for the random bytes
- * @max: the maximum number of bytes to write to @dest
+ * tpm1_get_random() - Get random bytes from the TPM's RNG
*
- * Return:
- * * number of bytes read
- * * -errno (positive TPM return codes are masked to -EIO)
+ * This is an internal function for tpm_get_random(). See its documentation
+ * for more information.
*/
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
- struct tpm1_get_random_out *out;
- u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
+ struct tpm1_get_random_out *resp;
struct tpm_buf buf;
- u32 total = 0;
- int retries = 5;
u32 recd;
int rc;
+ if (!dest || !max || max > TPM_MAX_RNG_DATA)
+ return -EINVAL;
+
rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
if (rc)
return rc;
- do {
- tpm_buf_append_u32(&buf, num_bytes);
-
- rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
- "attempting get random");
- if (rc) {
- if (rc > 0)
- rc = -EIO;
- goto out;
- }
+ tpm_buf_append_u32(&buf, max);
- out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
+ rc = tpm_transmit_cmd(chip, &buf, sizeof(resp->rng_data_len), "TPM_GetRandom");
+ if (rc) {
+ if (rc > 0)
+ rc = -EIO;
+ goto out;
+ }
- recd = be32_to_cpu(out->rng_data_len);
- if (recd > num_bytes) {
- rc = -EFAULT;
- goto out;
- }
+ resp = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
- if (tpm_buf_length(&buf) < TPM_HEADER_SIZE +
- sizeof(out->rng_data_len) + recd) {
- rc = -EFAULT;
- goto out;
- }
- memcpy(dest, out->rng_data, recd);
+ recd = be32_to_cpu(resp->rng_data_len);
+ if (recd > max) {
+ rc = -EIO;
+ goto out;
+ }
- dest += recd;
- total += recd;
- num_bytes -= recd;
+ if (buf.length < TPM_HEADER_SIZE + sizeof(resp->rng_data_len) + recd) {
+ rc = -EIO;
+ goto out;
+ }
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
- } while (retries-- && total < max);
+ memcpy(dest, resp->rng_data, recd);
+ tpm_buf_destroy(&buf);
+ return recd;
- rc = total ? (int)total : -EIO;
out:
tpm_buf_destroy(&buf);
return rc;
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 3a77be7ebf4a..5f15d8a93e23 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -244,98 +244,79 @@ struct tpm2_get_random_out {
} __packed;
/**
- * tpm2_get_random() - get random bytes from the TPM RNG
+ * tpm2_get_random() - Get random bytes from the TPM's 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)
+ * This is an internal function for tpm_get_random(). See its documentation
+ * for more information.
*/
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
- struct tpm2_get_random_out *out;
+ struct tpm2_get_random_out *resp;
struct tpm_header *head;
struct tpm_buf buf;
+ off_t offset;
u32 recd;
- u32 num_bytes = max;
int err;
- int total = 0;
- int retries = 5;
- u8 *dest_ptr = dest;
- off_t offset;
- if (!num_bytes || max > TPM_MAX_RNG_DATA)
+ if (!dest || !max || max > TPM_MAX_RNG_DATA)
return -EINVAL;
err = tpm2_start_auth_session(chip);
if (err)
return err;
- err = tpm_buf_init(&buf, 0, 0);
+ err = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
if (err) {
tpm2_end_auth_session(chip);
return err;
}
- do {
- tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
- if (tpm2_chip_auth(chip)) {
- tpm_buf_append_hmac_session(chip, &buf,
- TPM2_SA_ENCRYPT |
- TPM2_SA_CONTINUE_SESSION,
- NULL, 0);
- } else {
- offset = buf.handles * 4 + TPM_HEADER_SIZE;
- head = (struct tpm_header *)buf.data;
- if (tpm_buf_length(&buf) == offset)
- head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
- }
- tpm_buf_append_u16(&buf, num_bytes);
- err = tpm_buf_fill_hmac_session(chip, &buf);
- if (err) {
- tpm_buf_destroy(&buf);
- return err;
- }
+ if (tpm2_chip_auth(chip)) {
+ tpm_buf_append_hmac_session(chip, &buf,
+ TPM2_SA_ENCRYPT | TPM2_SA_CONTINUE_SESSION,
+ NULL, 0);
+ } else {
+ head = (struct tpm_header *)buf.data;
+ head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
+ }
+ tpm_buf_append_u16(&buf, max);
- err = tpm_transmit_cmd(chip, &buf,
- offsetof(struct tpm2_get_random_out,
- buffer),
- "attempting get random");
- err = tpm_buf_check_hmac_response(chip, &buf, err);
- if (err) {
- if (err > 0)
- err = -EIO;
- goto out;
- }
+ err = tpm_buf_fill_hmac_session(chip, &buf);
+ if (err) {
+ tpm_buf_destroy(&buf);
+ return err;
+ }
- head = (struct tpm_header *)buf.data;
- offset = TPM_HEADER_SIZE;
- /* Skip the parameter size field: */
- if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
- offset += 4;
-
- out = (struct tpm2_get_random_out *)&buf.data[offset];
- 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);
+ err = tpm_transmit_cmd(chip, &buf, offsetof(struct tpm2_get_random_out, buffer),
+ "TPM2_GetRandom");
- dest_ptr += recd;
- total += recd;
- num_bytes -= recd;
- } while (retries-- && total < max);
+ err = tpm_buf_check_hmac_response(chip, &buf, err);
+ if (err) {
+ if (err > 0)
+ err = -EIO;
- tpm_buf_destroy(&buf);
+ goto out;
+ }
+
+ head = (struct tpm_header *)buf.data;
+ offset = TPM_HEADER_SIZE;
+
+ /* Skip the parameter size field: */
+ if (be16_to_cpu(head->tag) == TPM2_ST_SESSIONS)
+ offset += 4;
+
+ resp = (struct tpm2_get_random_out *)&buf.data[offset];
+ recd = min_t(u32, be16_to_cpu(resp->size), max);
+
+ if (tpm_buf_length(&buf) <
+ TPM_HEADER_SIZE + offsetof(struct tpm2_get_random_out, buffer) + recd) {
+ err = -EIO;
+ goto out;
+ }
+
+ memcpy(dest, resp->buffer, recd);
+ return recd;
- return total ? total : -EIO;
out:
tpm_buf_destroy(&buf);
tpm2_end_auth_session(chip);
--
2.52.0
next prev parent reply other threads:[~2026-01-25 19:25 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-25 19:25 [PATCH v9 00/11] Streamline TPM2 HMAC sessions Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 01/11] KEYS: trusted: Use get_random-fallback for TPM Jarkko Sakkinen
2026-01-29 16:18 ` Roberto Sassu
2026-02-01 22:25 ` Jarkko Sakkinen
2026-02-20 18:04 ` Mimi Zohar
2026-02-20 18:30 ` Chris Fenner
2026-03-03 21:32 ` Jarkko Sakkinen
2026-03-05 15:37 ` Mimi Zohar
2026-03-18 17:36 ` Chris Fenner
2026-03-19 14:28 ` Mimi Zohar
2026-03-23 5:26 ` Jarkko Sakkinen
2026-03-23 5:34 ` Jarkko Sakkinen
2026-03-23 5:46 ` Jarkko Sakkinen
2026-03-23 5:24 ` Jarkko Sakkinen
2026-03-03 21:30 ` Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 02/11] KEYS: trusted: Use get_random_bytes_wait() instead of tpm_get_random() Jarkko Sakkinen
2026-01-25 19:25 ` Jarkko Sakkinen [this message]
2026-01-25 19:25 ` [PATCH v9 04/11] tpm2-sessions: Define TPM2_NAME_MAX_SIZE Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 05/11] KEYS: trusted: Open code tpm2_buf_append() Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 06/11] KEYS: trusted: Remove dead branch from tpm2_unseal_cmd Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 07/11] KEYS: trusted: Re-orchestrate tpm2_read_public() calls Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 08/11] tpm2-sessions: Remove the support for more than one authorization Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 09/11] tpm-buf: Remove tpm_buf_append_handle Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 10/11] tpm-buf: Merge TPM_BUF_BOUNDARY_ERROR and TPM_BUF_OVERFLOW Jarkko Sakkinen
2026-01-25 19:25 ` [PATCH v9 11/11] tpm-buf: Implement managed allocations Jarkko Sakkinen
2026-02-08 14:09 ` Jarkko Sakkinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260125192526.782202-4-jarkko@kernel.org \
--to=jarkko@kernel.org \
--cc=James.Bottomley@HansenPartnership.com \
--cc=davem@davemloft.net \
--cc=dhowells@redhat.com \
--cc=ebiggers@kernel.org \
--cc=herbert@gondor.apana.org.au \
--cc=jmorris@namei.org \
--cc=keyrings@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=paul@paul-moore.com \
--cc=serge@hallyn.com \
--cc=zohar@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox