From: Jarkko Sakkinen <jarkko@kernel.org>
To: Srish Srinivasan <ssrish@linux.ibm.com>
Cc: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org,
James.Bottomley@hansenpartnership.com, zohar@linux.ibm.com,
stefanb@linux.ibm.com, linux-kernel@vger.kernel.org,
linux-security-module@vger.kernel.org, nayna@linux.ibm.com,
rnsastry@linux.ibm.com
Subject: Re: [PATCH v3] keys/trusted/tpm2: Validate TPM2_Create object sizes separately
Date: Fri, 2 Oct 2026 06:24:35 +0300 [thread overview]
Message-ID: <ar8j89aTa5H2t18h@kernel.org> (raw)
In-Reply-To: <d0079240-f97f-4cfe-b26d-2ad2b88ab3b7@linux.ibm.com>
On Wed, Sep 30, 2026 at 11:22:02AM +0530, Srish Srinivasan wrote:
>
> On 9/30/26 2:45 AM, Jarkko Sakkinen wrote:
> > On Sun, Sep 27, 2026 at 12:12:03AM +0530, Srish Srinivasan wrote:
> > > TPM2_Create returns outPrivate, outPublic, creationData, creationHash and
> > > creationTicket in its response parameter area. However, only outPrivate and
> > > outPublic are included in the trusted key blob. The size of the blob is
> > > therefore not determined by the size of the complete response parameter
> > > area.
> > >
> > > tpm2_seal_trusted() currently compares the size of the complete response
> > > parameter area against MAX_BLOB_SIZE. This can reject a valid response
> > > when the remaining response outputs cause the entire response parameter
> > > area to exceed MAX_BLOB_SIZE, even though the outPrivate and outPublic
> > > TPM2B structures consumed by tpm2_key_encode() remain small enough to be
> > > encoded in the key blob.
> > >
> > > This is observed when creating larger trusted keys using the swtpm TPM 2.0
> > > emulator backed by libtpms.
> > >
> > > For example, requesting a 113-byte key succeeds, 114 fails.
> > >
> > > ~$ keyctl add trusted trusted_key1 "new 113 keyhandle=0x81000001" @u
> > > 520504613
> > > ~$ keyctl add trusted trusted_key2 "new 114 keyhandle=0x81000001" @u
> > > add_key: Argument list too long
> > > ~$
> > >
> > > Remove the MAX_BLOB_SIZE check on the complete response parameter area.
> > > Instead, use the response length passed to tpm2_key_encode() to validate
> > > that the outPrivate and outPublic TPM2B structures are fully contained
> > > in the response before accessing them.
> > >
> > > Previously, a response parameter area larger than MAX_BLOB_SIZE was
> > > rejected with -E2BIG before ASN.1 encoding. With this change, if the
> > > resulting encoded blob does not fit in payload->blob, the error returned by
> > > asn1_encode_sequence() is propagated instead.
> > >
> > > Also, use scope-based cleanup to simplify resource management.
> > >
> > > Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
> > > ---
> > > Changelog:
> > >
> > > v3:
> > > - Simplify the TPM2B_PRIVATE and TPM2B_PUBLIC bounds checks
> > > - Use appropriate error codes for failure returns
> > > - Use scope-based cleanup to simplify resource management
> > >
> > > v2:
> > > - Exclude a comment pointed out by Jarkko
> > >
> > > security/keys/trusted-keys/trusted_tpm2.c | 42 +++++++++++++----------
> > > 1 file changed, 24 insertions(+), 18 deletions(-)
> > >
> > > diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
> > > index 906700c3d7f0..920f45c7864b 100644
> > > --- a/security/keys/trusted-keys/trusted_tpm2.c
> > > +++ b/security/keys/trusted-keys/trusted_tpm2.c
> > > @@ -25,24 +25,36 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
> > > {
> > > struct trusted_key_tpm *private = options->private;
> > > const int SCRATCH_SIZE = PAGE_SIZE;
> > > - u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL);
> > > - u8 *work = scratch, *work1;
> > > - u8 *end_work = scratch + SCRATCH_SIZE;
> > > + u8 *scratch __free(kfree) = NULL;
> > > + u8 *work, *work1;
> > > + u8 *end_work;
> > > u8 *priv, *pub;
> > > - u16 priv_len, pub_len;
> > > + u32 priv_len, pub_len;
> > > int ret;
> > > + if (len < 4)
> > > + return -EINVAL;
> > > +
> > > priv_len = get_unaligned_be16(src) + 2;
> > > - priv = src;
> > > + if (priv_len + 2 > len)
> > > + return -EIO;
> > > + priv = src;
> > > src += priv_len;
> > > pub_len = get_unaligned_be16(src) + 2;
> > > + if (pub_len + priv_len > len)
> > > + return -EIO;
> > > +
> > > pub = src;
> > > + scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL);
> > > if (!scratch)
> > > return -ENOMEM;
> > > + work = scratch;
> > > + end_work = scratch + SCRATCH_SIZE;
> > > +
> > > work = asn1_encode_oid(work, end_work, tpm2key_oid,
> > > asn1_oid_len(tpm2key_oid));
> > > @@ -50,10 +62,9 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
> > > unsigned char bool[3], *w = bool;
> > > /* tag 0 is emptyAuth */
> > > w = asn1_encode_boolean(w, w + sizeof(bool), true);
> > > - if (WARN(IS_ERR(w), "BUG: Boolean failed to encode")) {
> > > - ret = PTR_ERR(w);
> > > - goto err;
> > > - }
> > > + if (WARN(IS_ERR(w), "BUG: Boolean failed to encode"))
> > > + return PTR_ERR(w);
> > > +
> > > work = asn1_encode_tag(work, end_work, 0, bool, w - bool);
> > > }
> > > @@ -65,8 +76,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
> > > */
> > > if (WARN(work - scratch + pub_len + priv_len + 14 > SCRATCH_SIZE,
> > > "BUG: scratch buffer is too small")) {
> > > - ret = -EINVAL;
> > > - goto err;
> > > + return -EINVAL;
> > > }
> > > work = asn1_encode_integer(work, end_work, private->keyhandle);
> > > @@ -79,15 +89,10 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
> > > if (IS_ERR(work1)) {
> > > ret = PTR_ERR(work1);
> > > pr_err("BUG: ASN.1 encoder failed with %d\n", ret);
> > > - goto err;
> > > + return ret;
> > > }
> > > - kfree(scratch);
> > > return work1 - payload->blob;
> > > -
> > > -err:
> > > - kfree(scratch);
> > > - return ret;
> > > }
> > > struct tpm2_key_context {
> > > @@ -340,10 +345,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> > > goto out;
> > > blob_len = tpm_buf_read_u32(buf, &offset);
> > > - if (blob_len > MAX_BLOB_SIZE || buf->flags & TPM_BUF_INVALID) {
> > > + if (buf->flags & TPM_BUF_INVALID) {
> > > rc = -E2BIG;
> > > goto out;
> > > }
> > > +
> > > if (buf->length - offset < blob_len) {
> > > rc = -EFAULT;
> > > goto out;
> > > --
> > > 2.53.0
> > >
> > Now we can say that it leaves the tree to cleaner state than it was
> > before applying this patch. The first version, despite doing the right
> > thing was simply too convoluted.
> >
> > Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
>
>
> Thanks for the review and for helping improve the patch, Jarkko.
sure, np :-)
Br, Jarkko
prev parent reply other threads:[~2026-10-02 3:24 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-26 18:42 Srish Srinivasan
2026-09-29 21:15 ` Jarkko Sakkinen
2026-09-30 5:52 ` Srish Srinivasan
2026-10-02 3:24 ` 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=ar8j89aTa5H2t18h@kernel.org \
--to=jarkko@kernel.org \
--cc=James.Bottomley@hansenpartnership.com \
--cc=keyrings@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=nayna@linux.ibm.com \
--cc=rnsastry@linux.ibm.com \
--cc=ssrish@linux.ibm.com \
--cc=stefanb@linux.ibm.com \
--cc=zohar@linux.ibm.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®