* [PATCH] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
@ 2026-07-18 20:28 Fabrice Derepas
2026-07-18 21:12 ` Richard Weinberger
2026-07-18 22:13 ` Jarkko Sakkinen
0 siblings, 2 replies; 7+ messages in thread
From: Fabrice Derepas @ 2026-07-18 20:28 UTC (permalink / raw)
To: keyrings, linux-integrity
Cc: Fabrice Derepas, david, upstream+dcp, jarkko, zohar, dhowells
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.
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
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
1 sibling, 0 replies; 7+ messages in thread
From: Richard Weinberger @ 2026-07-18 21:12 UTC (permalink / raw)
To: keyrings, linux-integrity, upstream, Fabrice Derepas
Cc: Fabrice Derepas, david, upstream+dcp, jarkko, zohar, dhowells
On Samstag, 18. Juli 2026 22:28 'Fabrice Derepas' via upstream 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.
Hmm, but this will only overflow p->blob[], which is the attacker input.
p->blob[] is at least 512 bytes long.
So an attacker is only able to overwrite it's own provided input?
> 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.
Since the DCP engine is only found on tiny 32-bits NXP i.MX systems,
I don't consider this a real issue.
> 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.
While I welcome the proposed changes as they make the code more clear
and will other tools happy, I don't think it's a security issue.
So the commit message needs rewording.
Thanks,
//richard
--
sigma star gmbh | Eduard-Bodem-Gasse 6, 6020 Innsbruck, AUT UID/VAT Nr:
ATU 66964118 | FN: 374287y
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
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
1 sibling, 1 reply; 7+ messages in thread
From: Jarkko Sakkinen @ 2026-07-18 22:13 UTC (permalink / raw)
To: Fabrice Derepas
Cc: keyrings, linux-integrity, david, upstream+dcp, zohar, dhowells
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.
BR, Jarkko
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
2026-07-18 22:13 ` Jarkko Sakkinen
@ 2026-07-18 22:16 ` Jarkko Sakkinen
2026-07-19 13:44 ` Fabrice Derepas
2026-07-19 16:39 ` [PATCH v2] " Fabrice Derepas
0 siblings, 2 replies; 7+ messages in thread
From: Jarkko Sakkinen @ 2026-07-18 22:16 UTC (permalink / raw)
To: Fabrice Derepas
Cc: keyrings, linux-integrity, david, upstream+dcp, zohar, dhowells
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
2026-07-18 22:16 ` Jarkko Sakkinen
@ 2026-07-19 13:44 ` Fabrice Derepas
2026-07-19 16:39 ` [PATCH v2] " Fabrice Derepas
1 sibling, 0 replies; 7+ messages in thread
From: Fabrice Derepas @ 2026-07-19 13:44 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Richard Weinberger, keyrings, linux-integrity, david,
upstream+dcp, zohar, dhowells
On Sun, Jul 19, 2026, Jarkko Sakkinen wrote:
> 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.
Agreed, thanks. You and Richard are right that this is not an
exploitable OOB due to the struct layout.
For v2 I'll:
- reframe the commit message as a correctness/hardening fix and drop
the exploitation and "how this was found" paragraphs;
- add the Fixes: tags myself (they both trace to the DCP trusted-keys
introduction) so you don't have to dig them up;
- keep the code changes as-is.
Will send v2 shortly.
Thanks,
Fabrice
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
2026-07-18 22:16 ` Jarkko Sakkinen
2026-07-19 13:44 ` Fabrice Derepas
@ 2026-07-19 16:39 ` Fabrice Derepas
2026-07-19 16:53 ` Richard Weinberger
1 sibling, 1 reply; 7+ messages in thread
From: Fabrice Derepas @ 2026-07-19 16:39 UTC (permalink / raw)
To: keyrings, linux-integrity
Cc: Fabrice Derepas, david, upstream+dcp, jarkko, zohar, dhowells
Two correctness and type-hygiene issues exist in the DCP trusted keys
implementation.
First, trusted_dcp_unseal() reads p->key_len from a user-supplied blob
without checking if it exceeds MAX_KEY_SIZE. If a crafted blob provides
a payload_len larger than 128, the subsequent do_aead_crypto() call
writes past the end of the p->key array into the adjacent p->blob
buffer within the same struct trusted_key_payload -- the caller's own
input, not unrelated kernel memory. While not exploitable, this
violates strict array bounds and triggers static analyzers. Fix this by adding a validation check against
MIN_KEY_SIZE and MAX_KEY_SIZE immediately after reading the length,
matching the checks already done in trusted_core.c.
Second, calc_blob_len() calculates a sum in size_t that truncates to
unsigned int on 64-bit platforms. Because the DCP hardware is only
present on 32-bit i.MX SoC platforms, size_t and unsigned int are
functionally equivalent in production, making this truncation harmless in
practice. Nevertheless, updating the return type to size_t (and
subsequently updating 'blen' in the seal/unseal paths) resolves
type-narrowing warnings and improves overall code hygiene.
Fixes: 2e8a0f40a39c ("KEYS: trusted: Introduce NXP DCP-backed trusted keys")
Signed-off-by: Fabrice Derepas <fabrice.derepas@canonical.com>
---
Changes in v2:
- Reframed commit message as correctness/hardening fix (Richard, Jarkko)
- Changed bare return -EINVAL to goto out for consistency
- Added Fixes tag
Compile-tested with arm-linux-gnueabihf-gcc on imx_v6_v7_defconfig
with CONFIG_TRUSTED_KEYS_DCP=y (W=1, zero warnings). No DCP hardware
available for runtime testing.
security/keys/trusted-keys/trusted_dcp.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/trusted-keys/trusted_dcp.c
index 7b6eb655d..c078adebe 100644
--- a/security/keys/trusted-keys/trusted_dcp.c
+++ b/security/keys/trusted-keys/trusted_dcp.c
@@ -69,7 +69,7 @@ static bool skip_zk_test;
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 encrypt_blob_key(u8 *plain_key, u8 *encrypted_key)
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,7 +243,8 @@ static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
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) {
@@ -253,9 +255,14 @@ static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
}
p->key_len = le32_to_cpu(b->payload_len);
+ if (p->key_len < MIN_KEY_SIZE || p->key_len > MAX_KEY_SIZE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
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;
base-commit: 6d41c11ef3044788902a05e292cd7f0a9c7a8157
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2] KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
2026-07-19 16:39 ` [PATCH v2] " Fabrice Derepas
@ 2026-07-19 16:53 ` Richard Weinberger
0 siblings, 0 replies; 7+ messages in thread
From: Richard Weinberger @ 2026-07-19 16:53 UTC (permalink / raw)
To: keyrings, linux-integrity, upstream
Cc: Fabrice Derepas, david, upstream+dcp, jarkko, zohar, dhowells,
Fabrice Derepas
On Sonntag, 19. Juli 2026 18:39 'Fabrice Derepas' via upstream wrote:
> Two correctness and type-hygiene issues exist in the DCP trusted keys
> implementation.
>
> First, trusted_dcp_unseal() reads p->key_len from a user-supplied blob
> without checking if it exceeds MAX_KEY_SIZE. If a crafted blob provides
> a payload_len larger than 128, the subsequent do_aead_crypto() call
> writes past the end of the p->key array into the adjacent p->blob
> buffer within the same struct trusted_key_payload -- the caller's own
> input, not unrelated kernel memory. While not exploitable, this
> violates strict array bounds and triggers static analyzers. Fix this by adding a validation check against
> MIN_KEY_SIZE and MAX_KEY_SIZE immediately after reading the length,
> matching the checks already done in trusted_core.c.
>
> Second, calc_blob_len() calculates a sum in size_t that truncates to
> unsigned int on 64-bit platforms. Because the DCP hardware is only
> present on 32-bit i.MX SoC platforms, size_t and unsigned int are
> functionally equivalent in production, making this truncation harmless in
> practice. Nevertheless, updating the return type to size_t (and
> subsequently updating 'blen' in the seal/unseal paths) resolves
> type-narrowing warnings and improves overall code hygiene.
>
> Fixes: 2e8a0f40a39c ("KEYS: trusted: Introduce NXP DCP-backed trusted keys")
> Signed-off-by: Fabrice Derepas <fabrice.derepas@canonical.com>
Reviewed-by: Richard Weinberger <richard@nod.at>
Thanks,
//richard
--
sigma star gmbh | Eduard-Bodem-Gasse 6, 6020 Innsbruck, AUT UID/VAT Nr:
ATU 66964118 | FN: 374287y
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-19 16:53 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
2026-07-19 13:44 ` Fabrice Derepas
2026-07-19 16:39 ` [PATCH v2] " Fabrice Derepas
2026-07-19 16:53 ` Richard Weinberger
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.