This pull request contains bug fixes discussed in [1] and two fixes
 (in one commit) from Fabrice for DCP trusted keys backend..
 
 BR, Jarkko
 
 [1] https://lore.kernel.org/keyrings/amINZJVhEBwxEixP@kernel.org/
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRE6pSOnaBC00OEHEIaerohdGur0gUCamem9QAKCRAaerohdGur
 0nA1AQD4TMj2MpvOW4XREPB05JXeiYFkeDHKZ07o6tvPsTnuTgEA6pjY/Q5MqjLh
 gAUHzv5mjA4TvrERvDXC+6oh+wiWrwc=
 =bpHR
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2026-07-27 14:14:11 -07:00
commit aa6fc3defb
3 changed files with 21 additions and 11 deletions

View File

@ -255,7 +255,8 @@ assoc_array_walk(const struct assoc_array *array,
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);

View File

@ -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 @@ static int keyring_diff_objects(const void *object, const void *data)
return -1;
differ_plus_i:
level += i;
level += i - (int)sizeof(a->desc);
differ:
i = level * 8 + __ffs(seg_a ^ seg_b);
return i;

View File

@ -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;