From: Jarkko Sakkinen <jarkko@kernel.org>
To: Linus Torvalds <torvalds@linuxfoundation.org>
Cc: Jaewon Yang <yong010301@gmail.com>,
Peter Huewe <peterhuewe@gmx.de>, Jason Gunthorpe <jgg@ziepe.ca>,
linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
security@kernel.org
Subject: Re: [PATCH] tpm: Reject reads outside the response buffer
Date: Sat, 18 Jul 2026 21:17:33 +0300 [thread overview]
Message-ID: <alvDPToN5hXa3vXd@kernel.org> (raw)
In-Reply-To: <CAHk-=wi8aXM9=Y8othMb1oxTv-PDw4isj-FPbXu0MXsm_EPE1g@mail.gmail.com>
On Sat, Jul 11, 2026 at 11:58:14AM -0700, Linus Torvalds wrote:
> On Sat, 11 Jul 2026 at 10:09, Jarkko Sakkinen <jarkko@kernel.org> wrote:
> >
> > Please don't delegate the work for me that you should doing i.e.
> > looking at your reproducer and describing the scenario/sequence
> > that would lead to infeasible consequence.
>
> I don't understand this reply.
>
> The original email had all the relevant information: how to trigger
> the condition, what the bug is, and what's going on.
>
> The bug seems straightforward: the tpm code appears to blindly use a
> user-supplied 'loff_t' that is simply not checked. The email you
> responded to seems very clear on the issue:
>
> 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.
>
> So what's the problem here?
>
> Now, honestly, I think this tpm code is badly written to begin with,
> and the patch doesn't fix that fundamental issue.
>
> The code simply shouldn't change response_length by how much have been
> read, it should just use the fixed size of the buffer and compare it
> to the offset.
>
> And once the buffer has been fully used, we clean it up.
>
> Something ENTIRELY UNTESTED like the attached patch. But I do want to
> point out that this patch is
>
> (a) UNTESTED
>
> (b) bigger and more invasive than the simple "just check the offset"
>
> That said, I really don't like how the original patch by Jaewon
> depends on TPM_BUFSIZE when the real limit is that "response_length",
> but that's a direct result of the tpm code being disgustign and
> changing response_length as a response to partial reads.
>
> So the attached patch tries to fix that fundamental mistake, and in
> the process I think it makes the code more readable, but whatever. I
> probably think that primarily because I wrote the patch.
>
> Comments? But this "dismiss a patch based on bogus reasons" seems like
> a huge mistake.
>
> Again. The attached patch is UNTESTED.
>
> Linus
I hear you. I was probably too quick draw with this one.
> drivers/char/tpm/tpm-dev-common.c | 67 ++++++++++++++++++++++-----------------
> 1 file changed, 38 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
> index f942c0c8e402..f1c17fdea74d 100644
> --- a/drivers/char/tpm/tpm-dev-common.c
> +++ b/drivers/char/tpm/tpm-dev-common.c
> @@ -127,44 +127,53 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,
> file->private_data = priv;
> }
>
> +static inline ssize_t tpm_common_read_cleanup(struct file_priv *priv, loff_t *off, ssize_t ret)
> +{
> + *off = 0;
> + timer_delete_sync(&priv->user_read_timer);
> + flush_work(&priv->timeout_work);
> + return ret;
> +}
> +
> ssize_t tpm_common_read(struct file *file, char __user *buf,
> size_t size, loff_t *off)
> {
> struct file_priv *priv = file->private_data;
> - ssize_t ret_size = 0;
> - int rc;
> + ssize_t response_length;
> + u64 offset;
>
> - mutex_lock(&priv->buffer_mutex);
> + if (!size)
> + return 0;
>
> - if (priv->response_length) {
> - priv->response_read = true;
> + guard(mutex)(&priv->buffer_mutex);
> + response_length = priv->response_length;
>
> - ret_size = min_t(ssize_t, size, priv->response_length);
> - if (ret_size <= 0) {
> - priv->response_length = 0;
> - goto out;
> - }
> + // Error or nothing to read?
> + if (response_length <= 0)
> + return tpm_common_read_cleanup(priv, off, response_length);
>
> - rc = copy_to_user(buf, priv->data_buffer + *off, ret_size);
> - if (rc) {
> - memset(priv->data_buffer, 0, TPM_BUFSIZE);
> - priv->response_length = 0;
> - ret_size = -EFAULT;
> - } else {
> - memset(priv->data_buffer + *off, 0, ret_size);
> - priv->response_length -= ret_size;
> - *off += ret_size;
> - }
> - }
> + offset = *off;
>
> -out:
> - if (!priv->response_length) {
> - *off = 0;
> - timer_delete_sync(&priv->user_read_timer);
> - flush_work(&priv->timeout_work);
> - }
> - mutex_unlock(&priv->buffer_mutex);
> - return ret_size;
> + // Have we already read everything? Return EOF
> + if (offset >= response_length)
> + return tpm_common_read_cleanup(priv, off, 0);
> +
> + // Do the potentially partial read
> + size = min_t(size_t, size, response_length - offset);
> + size -= copy_to_user(buf, priv->data_buffer + offset, size);
> + if (!size)
> + return -EFAULT;
> + offset += size;
> +
> + // Are we all done with the response?
> + if (offset >= response_length)
> + return tpm_common_read_cleanup(priv, off, size);
> +
> + // We still have some data left, update the offset
> + // and be ready to read the rest later - don't do
> + // the cleanup.
> + *off = offset;
> + return size;
> }
>
> ssize_t tpm_common_write(struct file *file, const char __user *buf,
BR, Jarkko
prev parent reply other threads:[~2026-07-18 18:17 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
2026-07-18 18:17 ` Jarkko Sakkinen [this message]
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=alvDPToN5hXa3vXd@kernel.org \
--to=jarkko@kernel.org \
--cc=jgg@ziepe.ca \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peterhuewe@gmx.de \
--cc=security@kernel.org \
--cc=torvalds@linuxfoundation.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.