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

CVE-2026-98642

Affected Products

Linux