summaryrefslogtreecommitdiff
path: root/security/keys
diff options
context:
space:
mode:
authorMichael Bommarito <michael.bommarito@gmail.com>2026-07-19 12:15:03 -0400
committerJarkko Sakkinen <jarkko@kernel.org>2026-07-23 18:23:32 +0300
commit63918731f9ae25b5deb022f118e941e6dddfcef4 (patch)
tree21967925ebcceb8aa3c00a12cd7cfd56d306ed27 /security/keys
parent35d661c98fe4733490f20b4311616a3c2c30abc0 (diff)
keys: fix out-of-bounds read in keyring_get_key_chunk()
For description-level chunks keyring_get_key_chunk() advances the read pointer by level * sizeof(long) past the inline prefix but only bounds-checks the prefix, so a long enough key description is read past its kmemdup(desc, desc_len + 1) allocation. Compute the full byte offset and bounds-check the description against it before reading. The walk only reaches a description-level chunk when two keys collide through the hash, x, type and domain_tag chunks, so this is reached from an unprivileged add_key(2) with a crafted pair of same-type keys whose index hashes collide; KASAN reports a slab-out-of-bounds read. Fixes: f771fde82051 ("keys: Simplify key description management") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Tested-by: Jarkko Sakkinen <jarkko@kernel.org> Link: https://lore.kernel.org/r/20260719161505.2423935-2-michael.bommarito@gmail.com Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/keyring.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 7a2ee0ded7c9..085f7a743354 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -271,6 +271,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
unsigned long chunk = 0;
const u8 *d;
int desc_len = index_key->desc_len, n = sizeof(chunk);
+ unsigned int offset;
level /= ASSOC_ARRAY_KEY_CHUNK_SIZE;
switch (level) {
@@ -284,12 +285,12 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
return (unsigned long)index_key->domain_tag;
default:
level -= 4;
- if (desc_len <= sizeof(index_key->desc))
+ offset = sizeof(index_key->desc) + level * sizeof(long);
+ if (desc_len <= offset)
return 0;
- d = index_key->description + sizeof(index_key->desc);
- d += level * sizeof(long);
- desc_len -= sizeof(index_key->desc);
+ d = index_key->description + offset;
+ desc_len -= offset;
if (desc_len > n)
desc_len = n;
do {