CVE-2026-45838
Description
In the Linux kernel, the following vulnerability has been resolved:
bpf: fix end-of-list detection in cgroup_storage_get_next_key()
list_next_entry() never returns NULL -- when the current element is the last entry it wraps to the list head via container_of(). The subsequent NULL check is therefore dead code and get_next_key() never returns -ENOENT for the last element, instead reading storage->key from a bogus pointer that aliases internal map fields and copying the result to userspace.
Replace it with list_entry_is_head() so the function correctly returns -ENOENT when there are no more entries.
Affected products
2Patches
105828b9e5b272bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 8fca0c64f7b1cd..23267213a17fb7 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -270,7 +270,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
b4b5a20bed82bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index a04f505aefe9b6..c8b8dcc37ed4a7 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
85a2f30e40f7bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 3969eb0382afba..cfb4ff26105186 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
32ce55d42439bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index c93a756e035c02..b8db4fbd3bd2ae 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
fc39753b7f92bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 8fca0c64f7b1cd..23267213a17fb7 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -270,7 +270,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
32ce55d42439bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index c93a756e035c02..b8db4fbd3bd2ae 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
5828b9e5b272bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 8fca0c64f7b1cd..23267213a17fb7 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -270,7 +270,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
85a2f30e40f7bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 3969eb0382afba..cfb4ff26105186 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
b4b5a20bed82bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index a04f505aefe9b6..c8b8dcc37ed4a7 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -259,7 +259,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
fc39753b7f92bpf: fix end-of-list detection in cgroup_storage_get_next_key()
1 file changed · +1 −2
kernel/bpf/local_storage.c+1 −2 modifieddiff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c index 8fca0c64f7b1cd..23267213a17fb7 100644 --- a/kernel/bpf/local_storage.c +++ b/kernel/bpf/local_storage.c @@ -270,7 +270,7 @@ static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key, goto enoent; storage = list_next_entry(storage, list_map); - if (!storage) + if (list_entry_is_head(storage, &map->list, list_map)) goto enoent; } else { storage = list_first_entry(&map->list, -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Incorrect end-of-list detection: list_next_entry() never returns NULL, so the NULL check is dead code and the function reads from a bogus pointer when iterating past the last entry."
Attack vector
An attacker with the ability to iterate BPF cgroup storage map keys (e.g., via `bpf_map_get_next_key()` from userspace) can trigger this bug. When the last valid storage entry is reached, `list_next_entry()` wraps to the list head instead of returning NULL, so the dead NULL check is skipped. The function then reads `storage->key` from a bogus pointer that aliases internal map fields and copies that data to userspace, leaking kernel memory [patch_id=2654231]. No special privileges beyond the ability to iterate the map are required.
Affected code
The vulnerability is in `cgroup_storage_get_next_key()` in `kernel/bpf/local_storage.c` [patch_id=2654231]. The function uses `list_next_entry()` to advance through the cgroup storage map's linked list, but then checks `if (!storage)` to detect the end of the list — a check that can never be true because `list_next_entry()` wraps to the list head rather than returning NULL.
What the fix does
The patch replaces the dead `if (!storage)` check with `if (list_entry_is_head(storage, &map->list, list_map))` [patch_id=2654231]. The `list_entry_is_head()` macro correctly detects when the pointer has wrapped back to the list head, causing the function to return `-ENOENT` as intended. This closes the information leak by ensuring no out-of-bounds read occurs when iterating past the last entry.
Preconditions
- authThe attacker must be able to invoke bpf_map_get_next_key() on a BPF_MAP_TYPE_CGROUP_STORAGE map from userspace.
- inputThe cgroup storage map must have at least one entry so that iteration reaches the last element.
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- git.kernel.org/stable/c/32ce55d424395904986f5066f8755f6cb9993377nvd
- git.kernel.org/stable/c/5828b9e5b272ecff7cf5d345128d3de7324117f7nvd
- git.kernel.org/stable/c/85a2f30e40f7468db732f55659bc6318874f49afnvd
- git.kernel.org/stable/c/b4b5a20bed82130da2f2818f04d52378952fbd0bnvd
- git.kernel.org/stable/c/fc39753b7f92e09177777e9c648afe5aa3abb81fnvd
News mentions
0No linked articles in our index yet.