From: Jarkko Sakkinen <jarkko@kernel.org>
To: Jaewon Yang <yong010301@gmail.com>
Cc: Peter Huewe <peterhuewe@gmx.de>, Jason Gunthorpe <jgg@ziepe.ca>,
linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
security@kernel.org, linux-api@vger.kernel.org
Subject: Re: [PATCH v2] tpm: Make the TPM character devices non-seekable
Date: Sat, 18 Jul 2026 21:20:22 +0300 [thread overview]
Message-ID: <alvD5nOP15O5B8Ai@kernel.org> (raw)
In-Reply-To: <alvCRtFvf15hG7tJ@kernel.org>
oN Sat, Jul 18, 2026 at 09:13:30PM +0300, Jarkko Sakkinen wrote:
> On Mon, Jul 13, 2026 at 02:11:47AM +0900, Jaewon Yang wrote:
> > 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; and
> > - no KASAN report was produced.
> >
> > Fixes: 9488585b21be ("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>
> > ---
> > Changes in v2:
> > - replace the response-buffer bounds check with nonseekable_open();
> > - reject positional read and write at open time;
> > - preserve the existing sequential read/write state machine.
> >
> > The alternative response_length rework proposed during review was tested
> > and not taken: a read-until-EOF loop hangs because cleanup resets *off
> > without clearing response_length. It also treats an arbitrary positional
> > offset as the consumption cursor; for example,
> >
> > pread(fd, &c, 1, 99)
> >
> > on a 100-byte response can discard bytes 0 through 98 without returning
> > them.
> >
> > drivers/char/tpm/tpm-dev.c | 2 +-
> > drivers/char/tpm/tpmrm-dev.c | 2 +-
> > 2 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
> > index 2779a8738..74488f0a7 100644
> > --- a/drivers/char/tpm/tpm-dev.c
> > +++ b/drivers/char/tpm/tpm-dev.c
> > @@ -36,7 +36,7 @@ static int tpm_open(struct inode *inode, struct file *file)
> >
> > tpm_common_open(file, chip, priv, NULL);
> >
> > - return 0;
> > + return nonseekable_open(inode, file);
> >
> > out:
> > clear_bit(0, &chip->is_open);
> > diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c
> > index f48d4d9e1..19e8f2779 100644
> > --- a/drivers/char/tpm/tpmrm-dev.c
> > +++ b/drivers/char/tpm/tpmrm-dev.c
> > @@ -29,7 +29,7 @@ static int tpmrm_open(struct inode *inode, struct file *file)
> >
> > tpm_common_open(file, chip, &priv->priv, &priv->space);
> >
> > - return 0;
> > + return nonseekable_open(inode, file);
> > }
> >
> > static int tpmrm_release(struct inode *inode, struct file *file)
> > --
> > 2.43.0
> >
>
> LGTM
>
>
> Acked-by: Jarkko Sakkinen <jarkko@kernel.org>
[A slow response time due on holiday until end of this Month.]
BR, Jarkko
next prev parent reply other threads:[~2026-07-18 18:20 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
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
2026-07-18 18:13 ` Jarkko Sakkinen
2026-07-18 18:20 ` Jarkko Sakkinen [this message]
2026-07-18 18:17 ` [PATCH] tpm: Reject reads outside the response buffer 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=alvD5nOP15O5B8Ai@kernel.org \
--to=jarkko@kernel.org \
--cc=jgg@ziepe.ca \
--cc=linux-api@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peterhuewe@gmx.de \
--cc=security@kernel.org \
--cc=yong010301@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.