diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-27 14:14:11 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-27 14:14:11 -0700 |
| commit | aa6fc3defb36b11eb82c4d1f4e95b5f6d8a0bca6 (patch) | |
| tree | de2512ae2853b64cbda81ad6e3740daac68b77f8 | |
| parent | e895a6fc204ff662bafe6b857f571424f1d17888 (diff) | |
| parent | a82c8a05e86f3f84e09698f65b4515b5d04633f6 (diff) | |
Merge tag 'for-next-keys-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd
Pull keys fixes from Jarkko Sakkinen:
- An unprivileged keyring whose keys collide through the
description-chunk path can drive assoc_array node splitting
into an out-of-bounds slot write. Fix it.
- Fix the DCP trusted keys backend
* tag 'for-next-keys-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
assoc_array: trim the final shortcut word using the current chunk end
keys: make keyring key-chunk byte order agree with keyring_diff_objects()
keys: fix out-of-bounds read in keyring_get_key_chunk()
KEYS: trusted: dcp: fix key_len validation and calc_blob_len() return type
| -rw-r--r-- | lib/assoc_array.c | 3 | ||||
| -rw-r--r-- | security/keys/keyring.c | 14 | ||||
| -rw-r--r-- | security/keys/trusted-keys/trusted_dcp.c | 15 |
3 files changed, 21 insertions, 11 deletions
diff --git a/lib/assoc_array.c b/lib/assoc_array.c index bcc6e0a013eb..b6c9723e12ce 100644 --- a/lib/assoc_array.c +++ b/lib/assoc_array.c @@ -255,7 +255,8 @@ follow_shortcut: sc_segments = shortcut->index_key[sc_level >> ASSOC_ARRAY_KEY_CHUNK_SHIFT]; dissimilarity = segments ^ sc_segments; - if (round_up(sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE) > shortcut->skip_to_level) { + if (shortcut->skip_to_level < round_down(sc_level, + ASSOC_ARRAY_KEY_CHUNK_SIZE) + ASSOC_ARRAY_KEY_CHUNK_SIZE) { /* Trim segments that are beyond the shortcut */ int shift = shortcut->skip_to_level & ASSOC_ARRAY_KEY_CHUNK_MASK; dissimilarity &= ~(ULONG_MAX << shift); diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 7a2ee0ded7c9..15bf4af8f282 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,17 +285,18 @@ 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; + d += desc_len; do { chunk <<= 8; - chunk |= *d++; + chunk |= *--d; } while (--desc_len > 0); return chunk; } @@ -375,7 +377,7 @@ same: return -1; differ_plus_i: - level += i; + level += i - (int)sizeof(a->desc); differ: i = level * 8 + __ffs(seg_a ^ seg_b); return i; diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/trusted-keys/trusted_dcp.c index 7b6eb655df0c..c078adebe190 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 @@ out: 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; |
