Linux Integrity Measurement development
 help / color / mirror / Atom feed
* [PATCH] tpm: Reject reads outside the response buffer
@ 2026-07-10  9:02 Jaewon Yang
  2026-07-11 17:08 ` Jarkko Sakkinen
  0 siblings, 1 reply; 5+ messages in thread
From: Jaewon Yang @ 2026-07-10  9:02 UTC (permalink / raw)
  To: Peter Huewe, Jarkko Sakkinen
  Cc: Jason Gunthorpe, linux-integrity, linux-kernel, security

tpm_common_read() clamps the transfer length to priv->response_length but
does not validate the file offset (*off) before using it to index the
fixed TPM_BUFSIZE-byte priv->data_buffer:

	ret_size = min_t(ssize_t, size, priv->response_length);
	copy_to_user(buf, priv->data_buffer + *off, ret_size);
	memset(priv->data_buffer + *off, 0, ret_size);

Sequential read() keeps *off in range, but the fops use the legacy .read
callback and neither tpm_open() nor tpmrm_open() calls nonseekable_open(),
so FMODE_PREAD stays set and pread(2) passes an arbitrary offset straight
into *off. An out-of-range offset then accesses memory beyond data_buffer,
causing an out-of-bounds read through copy_to_user() and, when the copy
succeeds, an out-of-bounds zero-write through memset().

Reject any read whose offset and length leave the response buffer.

Fixes: 9488585b21be ("tpm: add support for partial reads")
Cc: stable@vger.kernel.org
Signed-off-by: Jaewon Yang <yong010301@gmail.com>
---
Notes for reviewers (not part of the commit):

Reproduced on a KASAN 6.12 build with a swtpm TPM2 device. After a command
leaves a response pending, pread(fd, buf, 16, 0x1400) triggers two
slab-out-of-bounds reports, one for the copy_to_user() read and one for the
memset() write; on that x86-64 build the faulting access was 962 bytes past
a 4344-byte struct tpmrm_priv served from kmalloc-8k. With this patch,
out-of-range preads (offset past the buffer, at the end, or an in-range
offset whose length crosses the end) return -EINVAL with no KASAN report,
while sequential partial reads still return the full response and a normal
read after a rejected pread still works.

Reaching it needs a process that can open the TPM device and send a command.
Access depends on the device-node permissions; the upstream tpm2-tss udev
rules set tpmrm devices to mode 0660 with group tss. My reproduction ran as
root, so I have not shown non-root reach on a specific distribution or built
a privilege-escalation chain.

I searched public archives on 2026-07-10 and found no matching report, which
does not rule out a private, very recent, or unindexed one. Found through
AI-assisted source review; the code path and reproduction were verified by
hand. A reproducer and full logs are available on request.

 drivers/char/tpm/tpm-dev-common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
index f942c0c8e..dbf049028 100644
--- a/drivers/char/tpm/tpm-dev-common.c
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -145,6 +145,16 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
 			goto out;
 		}
 
+		/*
+		 * Reject reads whose offset and length fall outside the fixed
+		 * response buffer.
+		 */
+		if (*off < 0 || *off >= TPM_BUFSIZE ||
+		    ret_size > TPM_BUFSIZE - *off) {
+			ret_size = -EINVAL;
+			goto out;
+		}
+
 		rc = copy_to_user(buf, priv->data_buffer + *off, ret_size);
 		if (rc) {
 			memset(priv->data_buffer, 0, TPM_BUFSIZE);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-12 19:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10  9:02 [PATCH] tpm: Reject reads outside the response buffer Jaewon Yang
2026-07-11 17:08 ` Jarkko Sakkinen
2026-07-11 18:58   ` Linus Torvalds
2026-07-12 17:11     ` [PATCH v2] tpm: Make the TPM character devices non-seekable Jaewon Yang
2026-07-12 19:54       ` Linus Torvalds

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox