CVE-2026-64352CWE-416

CVE-2026-64352

High · published July 25, 2026

CVSS v3.1
7.8
EPSS
0%
Percentile
2.3
In the wild
Unconfirmed
What it is

In the Linux kernel, the following vulnerability has been resolved:

bpf: Allow LPM map access from sleepable BPF programs

trie_lookup_elem() annotates its rcu_dereference_check() walks with

only rcu_read_lock_bh_held(). Because rcu_dereference_check(p, c)

resolves to "c || rcu_read_lock_held()", this passes for XDP/NAPI and

classic RCU readers but fails for sleepable BPF programs, which enter

via __bpf_prog_enter_sleepable() and hold only rcu_read_lock_trace().

trie_update_elem() and trie_delete_elem() have the same problem in a

different form: they walk the trie with plain rcu_dereference(), which

asserts rcu_read_lock_held() unconditionally. Both are reachable from

sleepable BPF programs via the bpf_map_update_elem / bpf_map_delete_elem

helpers, and from the syscall path under classic rcu_read_lock(). In

the writer paths the trie is actually protected by trie->lock (an

rqspinlock taken across the walk); we never relied on the RCU read-side

lock to keep nodes alive there.

A sleepable LSM hook that ends up touching an LPM trie therefore

triggers lockdep on debug kernels:

=============================

WARNING: suspicious RCU usage

7.1.0-... Tainted: G E

-----------------------------

kernel/bpf/lpm_trie.c:249 suspicious rcu_dereference_check() usage!

1 lock held by net_tests/540:

#0: (rcu_tasks_trace_srcu_struct){....}-{0:0},

at: __bpf_prog_enter_sleepable+0x26/0x280

Call Trace:

dump_stack_lvl

lockdep_rcu_suspicious

trie_lookup_elem

bpf_prog_..._enforce_security_socket_connect

bpf_trampoline_...

security_socket_connect

__sys_connect

do_syscall_64

This is lockdep-only -- no UAF, since Tasks Trace RCU does serialize

against the trie's reclaim path -- but it spams the console once per

distinct callsite on every debug kernel running a sleepable BPF LSM

that touches an LPM trie, which is increasingly common.

For the lookup path, switch the rcu_dereference_check() annotation

from rcu_read_lock_bh_held() to bpf_rcu_lock_held(), which accepts all

three contexts (classic, BH, Tasks Trace). Other map types already

follow this convention.

For trie_update_elem() and trie_delete_elem(), annotate the walks as

rcu_dereference_protected(*p, 1) -- matching trie_free() in the same

file -- since trie->lock is held across the walk. rqspinlock has no

lockdep_map, so the predicate degenerates to '1' rather than

lockdep_is_held(&trie->lock); the protection is real but not

machine-verifiable. trie_get_next_key() also uses bare

rcu_dereference() but is reachable only from the BPF syscall, which

holds classic rcu_read_lock() before dispatching, so it is left

untouched.

The record
Technical detail
CVSS v3.1
7.8 · HIGH
Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CVSS v4.0
Not supplied
EPSS
0.00129 · 2.3th percentile
Weakness
CWE-416 · Use After Free
Published
2026-07-25T14:17Z
Affected products (6)
ProductVersionsFixed in
linux/linux_kernel≥ 5.14, < 5.15.2125.15.212
linux/linux_kernel≥ 5.16, < 6.1.1786.1.178
linux/linux_kernel≥ 6.2, < 6.6.1456.6.145
linux/linux_kernel≥ 6.7, < 6.12.976.12.97
linux/linux_kernel≥ 6.13, < 6.18.406.18.40
linux/linux_kernel≥ 6.19, < 7.1.47.1.4
References (7)
EPSS history
Timeline
  • 25 JUL 08:50Z
    bpf: Allow LPM map access from sleepable BPF programs
    cvelistv5