From: Jarkko Sakkinen <jarkko@kernel.org>
To: Fabrice Derepas <fabrice.derepas@canonical.com>
Cc: keyrings@vger.kernel.org, linux-integrity@vger.kernel.org,
david@sigma-star.at, upstream+dcp@sigma-star.at,
zohar@linux.ibm.com, dhowells@redhat.com
Subject: Re: [PATCH] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
Date: Sun, 19 Jul 2026 01:16:13 +0300 [thread overview]
Message-ID: <alv7LVoTQJOMyk2J@kernel.org> (raw)
In-Reply-To: <alv6fmIKjTBguKFE@kernel.org>
On Sun, Jul 19, 2026 at 01:13:23AM +0300, Jarkko Sakkinen wrote:
> On Sat, Jul 18, 2026 at 10:28:17PM +0200, Fabrice Derepas wrote:
> > Two defects in trusted_dcp_unseal() combine to allow a heap
> > out-of-bounds write in kernel context.
> >
> > The primary defect is a missing upper-bound check:
> > trusted_dcp_unseal() reads p->key_len from an attacker-supplied blob
> > with no validation that it is at most MAX_KEY_SIZE (128). It then
> > passes p->key_len + DCP_BLOB_AUTHLEN to do_aead_crypto() as the
> > operation length. Because p->key is only MAX_KEY_SIZE + 1 = 129
> > bytes, any payload_len above 128 in the blob overruns p->key. On
> > implementations where AES-128-GCM decryption writes plaintext before
> > verifying the authentication tag, up to 330 bytes of out-of-bounds
> > heap overwrite can occur before -EBADMSG is returned.
> >
> > The secondary defect is an integer overflow in calc_blob_len(), which
> > computes its sum in size_t but returns unsigned int, truncating the
> > result on 64-bit platforms. This allows a crafted blob with
> > payload_len near UINT_MAX to bypass the sanity check
> > (blen != p->blob_len). Due to a second wrap in the expression
> > p->key_len + DCP_BLOB_AUTHLEN (computed in unsigned int at the call
> > site), the len value that reaches do_aead_crypto() via this path is
> > at most 15 bytes and does not directly amplify the OOB write, but
> > the integrity check bypass must be fixed.
> >
> > Fix the primary OOB by validating p->key_len against MIN_KEY_SIZE
> > and MAX_KEY_SIZE immediately after reading it from the blob, matching
> > the validation already performed in trusted_core.c on the Opt_new
> > path. Fix the overflow by changing the return type of calc_blob_len()
> > to size_t; update the two blen declarations from int to size_t to
> > avoid narrowing-conversion warnings, and update the pr_err format
> > specifier for blen accordingly.
> >
> > The seal path is not affected: p->key_len is validated by
> > trusted_core.c before trusted_dcp_seal() is called, and the
> > blen > MAX_BLOB_SIZE guard provides defence in depth there.
> >
> > Exploitation requires high privileges. The unseal path is reached
> > via add_key("trusted", ..., KEY_SPEC_*) with the Opt_load command,
> > which requires write permission to a keyring that accepts trusted
> > keys -- in practice CAP_SYS_ADMIN. Additionally,
> > CONFIG_TRUSTED_KEYS_DCP must be enabled. The attacker must also supply
> > a crafted sealed blob, which in the typical dm-crypt use case means
> > either physical access to modify on-disk key material or a prior
> > compromise of a privileged process that writes the blob.
>
> This is hypothesis of an exploit at most.
>
> The change look while but this paragraph is way too abstract
> to qualify for anything.
>
> >
> > How this was found:
> > Found by applying the Squeeze Loop strategy ("The Squeeze Loop
> > Strategy: Catching Coherent-and-Wrong Artifacts with an
> > Author-Independent Executable Oracle," Zenodo
> > DOI 10.5281/zenodo.20787816, 2026) on its C terrain using
> > deductive verification. The formal proof of calc_blob_len (12/12
> > goals discharged) required a no_wrap precondition on payload_len;
> > removing that precondition caused 3 of 6 proof goals to fail.
> > Tracing the caller path confirmed the bounds bypass and the missing
> > key_len validation.
> >
> > Signed-off-by: Fabrice Derepas <fabrice.derepas@canonical.com>
> > ---
> > security/keys/trusted-keys/trusted_dcp.c | 13 ++++++++++---
> > 1 file changed, 9 insertions(+), 4 deletions(-)
> >
> > diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/trusted-keys/trusted_dcp.c
> > index XXXXXXXXXXXXXXXX..YYYYYYYYYYYYYYYY 100644
> > --- a/security/keys/trusted-keys/trusted_dcp.c
> > +++ b/security/keys/trusted-keys/trusted_dcp.c
> > @@ -69,7 +69,7 @@ module_param_named(dcp_skip_zk_test, skip_zk_test, bool, 0);
> > MODULE_PARM_DESC(dcp_skip_zk_test, "Don't test whether device keys are zero'ed");
> >
> > -static unsigned int calc_blob_len(unsigned int payload_len)
> > +static size_t calc_blob_len(unsigned int payload_len)
> > {
> > return sizeof(struct dcp_blob_fmt) + payload_len + DCP_BLOB_AUTHLEN;
> > }
> > @@ -200,7 +200,8 @@ static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
> > {
> > struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
> > - int blen, ret;
> > + size_t blen;
> > + int ret;
> > u8 *plain_blob_key;
> >
> > blen = calc_blob_len(p->key_len);
> > @@ -242,21 +243,25 @@ static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
> > {
> > struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
> > - int blen, ret;
> > + size_t blen;
> > + int ret;
> > u8 *plain_blob_key = NULL;
> >
> > if (b->fmt_version != DCP_BLOB_VERSION) {
> > pr_err("DCP blob has bad version: %i, expected %i\n",
> > b->fmt_version, DCP_BLOB_VERSION);
> > ret = -EINVAL;
> > goto out;
> > }
> >
> > p->key_len = le32_to_cpu(b->payload_len);
> > + if (p->key_len < MIN_KEY_SIZE || p->key_len > MAX_KEY_SIZE)
> > + return -EINVAL;
> > +
> > blen = calc_blob_len(p->key_len);
> > if (blen != p->blob_len) {
> > - pr_err("DCP blob has bad length: %i != %i\n", blen,
> > + pr_err("DCP blob has bad length: %zu != %u\n", blen,
> > p->blob_len);
> > ret = -EINVAL;
> > goto out;
> > --
> > 2.43.0
>
> As said, code changes themselves look reasonable but the commit message
> is painting a picture of impact that this bug really does not have.
If possible strip down the paragraph and add fixes tags (if possible,
I can dig it up too). With those requests send v2.
BR, Jarkko
next prev parent reply other threads:[~2026-07-18 22:16 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-18 20:28 [PATCH] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type Fabrice Derepas
2026-07-18 21:12 ` Richard Weinberger
2026-07-18 22:13 ` Jarkko Sakkinen
2026-07-18 22:16 ` Jarkko Sakkinen [this message]
2026-07-19 13:44 ` Fabrice Derepas
2026-07-19 16:39 ` [PATCH v2] " Fabrice Derepas
2026-07-19 16:53 ` Richard Weinberger
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=alv7LVoTQJOMyk2J@kernel.org \
--to=jarkko@kernel.org \
--cc=david@sigma-star.at \
--cc=dhowells@redhat.com \
--cc=fabrice.derepas@canonical.com \
--cc=keyrings@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=upstream+dcp@sigma-star.at \
--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 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.