[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <jecgeh5dmurb6dwzbfgc3agenfsuhwyzslqcvbh3rlbtgvyqzk@ljkuaxtm5rch>
Date: Mon, 22 Sep 2025 09:58:46 +0200
From: Stefano Garzarella <sgarzare@...hat.com>
To: Jarkko Sakkinen <jarkko@...nel.org>
Cc: linux-integrity@...r.kernel.org, Stefan Berger <stefanb@...ux.ibm.com>,
Jarkko Sakkinen <jarkko.sakkinen@...nsys.com>, Peter Huewe <peterhuewe@....de>, Jason Gunthorpe <jgg@...pe.ca>,
James Bottomley <James.Bottomley@...senpartnership.com>, Mimi Zohar <zohar@...ux.ibm.com>,
David Howells <dhowells@...hat.com>, Paul Moore <paul@...l-moore.com>,
James Morris <jmorris@...ei.org>, "Serge E. Hallyn" <serge@...lyn.com>,
open list <linux-kernel@...r.kernel.org>, "open list:KEYS-TRUSTED" <keyrings@...r.kernel.org>,
"open list:SECURITY SUBSYSTEM" <linux-security-module@...r.kernel.org>
Subject: Re: [PATCH v7] tpm: Make TPM buffer allocations more robust
On Fri, Sep 19, 2025 at 06:32:43PM +0300, Jarkko Sakkinen wrote:
>On Fri, Sep 19, 2025 at 03:35:43PM +0200, Stefano Garzarella wrote:
>> On Fri, Sep 19, 2025 at 02:24:47PM +0300, Jarkko Sakkinen wrote:
>> > From: Jarkko Sakkinen <jarkko.sakkinen@...nsys.com>
>> >
>> > Drop 'tpm_buf_init', 'tpm_buf_init_sized' and 'tpm_buf_free'. Refine
>> > 'struct tpm_buf' to hold capacity in order to enable stack allocation and
>> > sizes other than page size.
>> >
>> > The updated 'struct tpm_buf' can be allocated either from stack or heap.
>> >
>> > The contract is the following:
>> >
>> > 1. 'tpm_buf_reset' and 'tpm_buf_reset_size' expect that on the first run
>> > the passed buffer is zeroed by the caller (e.g. via memset or kzalloc).
>> > 2. The same buffer can be reused. On the second and subsequent resets the
>> > aforementioned functions verify that 'buf_size' has the same value, and
>> > emits warning if not.
>> >
>> > As a consequence 'struct tpm_buf' instance can be easily wrapped into
>> > managed allocation:
>> >
>> > struct tpm_buf *buf __free(kfree) buf = kzalloc(PAGE_SIZE,
>> > GFP_KERNEL);
>> >
>> > Reviewed-by: Stefan Berger <stefanb@...ux.ibm.com>
>> > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@...nsys.com>
>> > ---
>> > v7:
>> > - Additional function comments and invariant was unfortunately left to
>> > my staging area so here's the addition (does not affect functionality).
>> > v6:
>> > - Removed two empty lines as requested by Stefan:
>> > https://lore.kernel.org/linux-integrity/be1c5bef-7c97-4173-b417-986dc90d779c@linux.ibm.com/
>> > - Add 'capacity' field as this makes easy to stretch tpm_buf into stack
>> > allocation.
>> > v5:
>> > - I tested this version also with TPM 1.2 by booting up and checking
>> > that sysfs attributes work.
>> > - Fixed the length check against capacity (James) with TPM_BUF_CAPACITY.
>> > - Fixed declaration style: do it at the site (Jason).
>> > - Improved commit message (Stefan).
>> > - Removed "out" label from tpm2_pcr_read() (Stefan).
>> > - Removed spurious "return rc;" from tpm2_get_pcr_allocation() (Stefan).
>> > v4:
>> > - Wrote a more a descriptive short summary and improved description.
>> > - Fixed the error in documentation: there is 4090 bytes of space left
>> > for the payload - not 4088 bytes.
>> > - Turned tpm_buf_alloc() into inline function.
>> > v3:
>> > - Removed the cleanup class and moved on using __free(kfree) instead.
>> > - Removed `buf_size` (James).
>> > - I'm open for the idea of splitting still (Jason) but I'll hold
>> > at least this revision just to check that my core idea here
>> > is correct.
>> > v2:
>> > - Implement also memory allocation using the cleanup class.
>> > - Rewrote the commit message.
>> > - Implemented CLASS_TPM_BUF() helper macro.
>> > ---
>> > drivers/char/tpm/tpm-buf.c | 68 ++----
>> > drivers/char/tpm/tpm-sysfs.c | 19 +-
>> > drivers/char/tpm/tpm1-cmd.c | 143 ++++++------
>> > drivers/char/tpm/tpm2-cmd.c | 270 ++++++++++------------
>> > drivers/char/tpm/tpm2-sessions.c | 118 +++++-----
>> > drivers/char/tpm/tpm2-space.c | 42 ++--
>> > drivers/char/tpm/tpm_vtpm_proxy.c | 29 +--
>> > include/linux/tpm.h | 17 +-
>> > security/keys/trusted-keys/trusted_tpm1.c | 40 ++--
>> > security/keys/trusted-keys/trusted_tpm2.c | 153 ++++++------
>> > 10 files changed, 390 insertions(+), 509 deletions(-)
>> >
>> > diff --git a/drivers/char/tpm/tpm-buf.c b/drivers/char/tpm/tpm-buf.c
>> > index dc882fc9fa9e..19774bc5786f 100644
>> > --- a/drivers/char/tpm/tpm-buf.c
>> > +++ b/drivers/char/tpm/tpm-buf.c
>> > @@ -7,83 +7,57 @@
>> > #include <linux/module.h>
>> > #include <linux/tpm.h>
>> >
>> > -/**
>> > - * tpm_buf_init() - Allocate and initialize a TPM command
>> > - * @buf: A &tpm_buf
>> > - * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
>> > - * @ordinal: A command ordinal
>> > - *
>> > - * Return: 0 or -ENOMEM
>> > - */
>> > -int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
>> > -{
>> > - buf->data = (u8 *)__get_free_page(GFP_KERNEL);
>> > - if (!buf->data)
>> > - return -ENOMEM;
>> > -
>> > - tpm_buf_reset(buf, tag, ordinal);
>> > - return 0;
>> > -}
>> > -EXPORT_SYMBOL_GPL(tpm_buf_init);
>> > -
>> > /**
>> > * tpm_buf_reset() - Initialize a TPM command
>> > * @buf: A &tpm_buf
>> > + * @buf_size: Size of the buffer.
>> > * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
>> > * @ordinal: A command ordinal
>> > + *
>> > + * 1. Expects that on the first run the passed buffer is zeroed by the caller.
>> > + * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
>> > + * verified to be equal to the previous value.
>> > */
>> > -void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
>> > +void tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag, u32 ordinal)
>> > {
>> > struct tpm_header *head = (struct tpm_header *)buf->data;
>> >
>> > + WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
>> > WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
>> > tag != TPM2_ST_SESSIONS && tag != 0);
>> >
>> > buf->flags = 0;
>> > buf->length = sizeof(*head);
>> > + buf->capacity = buf_size - sizeof(*buf);
>> > + buf->handles = 0;
>> > head->tag = cpu_to_be16(tag);
>> > head->length = cpu_to_be32(sizeof(*head));
>> > head->ordinal = cpu_to_be32(ordinal);
>> > - buf->handles = 0;
>> > }
>> > EXPORT_SYMBOL_GPL(tpm_buf_reset);
>> >
>> > -/**
>> > - * tpm_buf_init_sized() - Allocate and initialize a sized (TPM2B) buffer
>> > - * @buf: A @tpm_buf
>> > - *
>> > - * Return: 0 or -ENOMEM
>> > - */
>> > -int tpm_buf_init_sized(struct tpm_buf *buf)
>> > -{
>> > - buf->data = (u8 *)__get_free_page(GFP_KERNEL);
>> > - if (!buf->data)
>> > - return -ENOMEM;
>> > -
>> > - tpm_buf_reset_sized(buf);
>> > - return 0;
>> > -}
>> > -EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
>> > -
>> > /**
>> > * tpm_buf_reset_sized() - Initialize a sized buffer
>> > * @buf: A &tpm_buf
>> > + * @buf_size: Size of the buffer.
>> > + *
>> > + * 1. Expects that on the first run the passed buffer is zeroed by the caller.
>> > + * 2. Old buffer can be reused. On the second and subsequent resets @buf_size is
>> > + * verified to be equal to the previous value.
>> > */
>> > -void tpm_buf_reset_sized(struct tpm_buf *buf)
>> > +void tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
>> > {
>> > + WARN_ON(buf->capacity != 0 && buf_size != (buf->capacity + sizeof(*buf)));
>> > +
>> > buf->flags = TPM_BUF_TPM2B;
>> > buf->length = 2;
>> > + buf->capacity = buf_size - sizeof(*buf);
>> > + buf->handles = 0;
>> > buf->data[0] = 0;
>> > buf->data[1] = 0;
>> > }
>> > EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
>> >
>> > -void tpm_buf_destroy(struct tpm_buf *buf)
>> > -{
>> > - free_page((unsigned long)buf->data);
>> > -}
>> > -EXPORT_SYMBOL_GPL(tpm_buf_destroy);
>> > -
>> > /**
>> > * tpm_buf_length() - Return the number of bytes consumed by the data
>> > * @buf: A &tpm_buf
>> *
>> * Return: The number of bytes consumed by the buffer
>> */
>> u32 tpm_buf_length(struct tpm_buf *buf)
>> {
>> return buf->length;
>> }
>> EXPORT_SYMBOL_GPL(tpm_buf_length);
>>
>> Should we update the return type (u16) on this function?
>
>Yes we should. Thanks for catching this.
>
>>
>> > @@ -108,7 +82,7 @@ void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
>> > if (buf->flags & TPM_BUF_OVERFLOW)
>> > return;
>> >
>> > - if ((buf->length + new_length) > PAGE_SIZE) {
>> > + if ((buf->length + new_length) > buf->capacity) {
>>
>> IIUC all of these are u16, so there could be an overflow when we do
>> `buf->length + new_length` ?
>>
>> Should we cast to u32 or just change the expression in something like
>> `new_length > (buf->capacity - buf->length)`
>
>Thanks, these really appropriate comments.
>
>I think best measure here would have hard constant cap of PAGE_SIZE
>for buf_size. That's how the specs limit anyhow. I'll extend the
>invariant.
Oh I see, that makes sense, thanks :-)
Stefano
Powered by blists - more mailing lists