---
id: CVE-2026-98642
title: 'bpf: Fix UAF due to concurrent consumption of ttrace lists in alloc_bulk'
summary: |-
  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…
severity: none
vendor: Linux
product: Linux
affected:
  - >-
    Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a <
    a0e150a118025a05c8662c536ba2a865da86419c
  - >-
    Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a <
    1d6581b544a88cf4348c2fb60dcb50ad63f012da
  - >-
    Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a <
    f101602415fb39a58941bec444df65634d5a6844
  - >-
    Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a <
    1c21452d02eec2f008e2c5535820f85adbd7587a
  - Linux 6.6
published: '2026-10-18'
updated: '2026-10-18'
sourceUpdated: '2026-10-18T15:20:13.740Z'
source: CVEORG
sourceUrl: 'https://www.cve.org/CVERecord?id=CVE-2026-98642'
references:
  - url: 'https://git.kernel.org/stable/c/a0e150a118025a05c8662c536ba2a865da86419c'
  - url: 'https://git.kernel.org/stable/c/1d6581b544a88cf4348c2fb60dcb50ad63f012da'
  - url: 'https://git.kernel.org/stable/c/f101602415fb39a58941bec444df65634d5a6844'
  - url: 'https://git.kernel.org/stable/c/1c21452d02eec2f008e2c5535820f85adbd7587a'
tags:
  - cve.org
ingestedAt: '2026-10-18T15:45:12.229Z'
---

## Overview

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.

## Affected

- `Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a < a0e150a118025a05c8662c536ba2a865da86419c`
- `Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a < 1d6581b544a88cf4348c2fb60dcb50ad63f012da`
- `Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a < f101602415fb39a58941bec444df65634d5a6844`
- `Linux >= 04fabf00b4d3aff5d010ecb617001814e409e24a < 1c21452d02eec2f008e2c5535820f85adbd7587a`
- `Linux 6.6`

## Remediation

Refer to the linked advisories for vendor-supplied fixes and affected version ranges.
