Skip to content

Commit f20d61c

Browse files
R4mbbtorvalds
authored andcommitted
tpm: Make the TPM character devices non-seekable
The TPM character devices expose a sequential command/response interface, but their open handlers leave FMODE_PREAD and FMODE_PWRITE enabled. After a command leaves a response pending, pread(fd, buf, 16, 0x1400) passes 0x1400 as *off to tpm_common_read(). The transfer length is bounded by response_length, but the offset is used unchecked when forming data_buffer + *off. A sufficiently large offset therefore causes an out-of-bounds heap read through copy_to_user() and, if the copy succeeds, an out-of-bounds zero-write through the following memset(). Positional I/O does not provide coherent semantics for this interface. An arbitrary pread offset cannot represent how much of a response has been consumed sequentially. The write callback always stores a command at the start of data_buffer, while pwrite() does not update file->f_pos and can leave the sequential read cursor stale. Call nonseekable_open() from both open handlers. This removes FMODE_PREAD and FMODE_PWRITE, causing positional reads and writes to fail with -ESPIPE before reaching the TPM callbacks, and explicitly marks the files non-seekable. Normal read() and write() continue to use the existing sequential f_pos cursor, leaving the response state machine unchanged. Tested on Linux 6.12 with KASAN and a swtpm TPM2 device: - sequential partial reads returned the complete response - pread() and preadv() with offset 0x1400 returned -ESPIPE - pwrite() and pwritev() with offset zero returned -ESPIPE - the pending response remained intact after the rejected operations - a subsequent normal command/response cycle completed normally - no KASAN report was produced. Fixes: 9488585 ("tpm: add support for partial reads") Link: https://lore.kernel.org/all/20260710090217.191289-1-yong010301@gmail.com/ Cc: stable@vger.kernel.org Signed-off-by: Jaewon Yang <yong010301@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 940d91c commit f20d61c

2 files changed

Lines changed: 2 additions & 2 deletions

File tree

drivers/char/tpm/tpm-dev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static int tpm_open(struct inode *inode, struct file *file)
3636

3737
tpm_common_open(file, chip, priv, NULL);
3838

39-
return 0;
39+
return nonseekable_open(inode, file);
4040

4141
out:
4242
clear_bit(0, &chip->is_open);

drivers/char/tpm/tpmrm-dev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ static int tpmrm_open(struct inode *inode, struct file *file)
2929

3030
tpm_common_open(file, chip, &priv->priv, &priv->space);
3131

32-
return 0;
32+
return nonseekable_open(inode, file);
3333
}
3434

3535
static int tpmrm_release(struct inode *inode, struct file *file)

0 commit comments

Comments
 (0)