PT-2026-116861 · Linux · Linux
CVE-2026-98642
·
Published
2026-10-18
·
Updated
2026-10-18
None
No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
In the Linux kernel, the following vulnerability has been resolved:
bpf: Fix UAF due to concurrent consumption of ttrace lists in alloc bulk
Syzkaller repeatedly triggered UAF splats related to nodes in
waiting for gp ttrace within the bpf memalloc:
BUG: KASAN: slab-use-after-free in llist del first+0x85/0x110 lib/llist.c:61
Read of size 8 at addr ffff8881572cd080 by task syz.4.470/5112
...
llist del first+0x85/0x110 lib/llist.c:61
alloc bulk+0x193/0x460 kernel/bpf/memalloc.c:229
bpf mem refill+0x386/0x560 kernel/bpf/memalloc.c:436
Freed by task 14:
...
free rcu kernel/bpf/memalloc.c:281 [inline]
free rcu tasks trace+0x48/0xd0 kernel/bpf/memalloc.c:291
rcu tasks invoke cbs+0x1ec/0x3e0 kernel/rcu/tasks.h:571
rcu tasks one gp+0x13d/0x220 kernel/rcu/tasks.h:621
rcu tasks kthread+0xf3/0x120 kernel/rcu/tasks.h:651
The reason is that the UAF occurs after the RCU Tasks Trace GP expires:
when the free rcu() callback runs, there is no synchronization
protecting llist del all() against concurrent alloc bulk() operating on
waiting for gp ttrace, leading to the race condition below:
CPU0 CPU1
free rcu (RCU Tasks Trace callback)
alloc bulk
llist del first(&c->waiting for gp ttrace)
entry = smp load acquire(&head->first);
do {
if (entry == NULL)
return NULL;
free all(llist del all(&c->waiting for gp ttrace))
llist for each safe(pos, t, llnode)
free one(pos);
next = READ ONCE(entry->next); <-- trigger UAF
} while (!try cmpxchg(&head->first, &entry, next));
In addition, there is also a theoretical race condition on the
free by rcu ttrace list. This race requires two preconditions: an
in-flight Tasks Trace GP keeping c->call rcu ttrace in progress == 1,
and concurrent cross-CPU frees repopulating c->free by rcu ttrace with
new nodes. Under these conditions, the following scenario triggers UAF:
// CPU0
// irq work is still busy (on PREEMPT RT)
alloc bulk()
llist del first(&c->free by rcu ttrace)
entry = smp load acquire(&head->first);
do {
if (entry == NULL)
return NULL;
// CPU1
bpf mem alloc destroy()
WRITE ONCE(c->draining, true)
// wait for CPU0
irq work sync()
// CPU2
do call rcu ttrace(tgt(CPU0))
if (c->draining) {
llist del all(&c->free by rcu ttrace)
free all()
}// CPU0 continue
next = READ ONCE(entry->next); <-- trigger UAF
while (!try cmpxchg(&head->first, &entry, next));
Fix this by introducing a raw spinlock to synchronize the concurrent
consumption on waiting for gp ttrace and free by rcu ttrace.
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Linux