---
id: "CVE-2026-98813"
kind: "vulnerability"
aliases: ["CVE-2026-98813"]
title: "Linux kernel: BPF map teardown can free BTF still in use, causing use-after-free"
severity: "unknown"
cvss: null
epss: null
exploited: false
status: "open"
category: "runtime"
products: []
ecosystems: []
tags: ["bpf", "kubernetes", "linux-kernel", "runtime", "self-hosted"]
not_affected_if: ["no-ebpf-programs-loaded"]
published_at: "2026-10-18T16:17:35+00:00"
first_seen_at: "2026-10-23T21:57:17+00:00"
updated_at: "2026-10-25T05:14:50+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-98813", "first_seen_at": "2026-10-23T21:57:17+00:00"}]
---

# Linux kernel: BPF map teardown can free BTF still in use, causing use-after-free

When a BPF hash map is freed while RCU callbacks are pending, the deferred destructor can read BTF memory that was already freed. The sources describe a kernel use-after-free (KASAN report) that can be reached by freeing a map with more elements than the allocator's high watermark.

_Summary, check and fix written by a model from the sources; labelled as such._

## How to check

- Check the running kernel version with `uname -r` and compare it against the fixed kernel versions in the NVD entry (unknown in the sources)
- Check whether BPF is in use: `bpftool map list` on hosts that load eBPF programs (unknown whether this is needed)

## Fix

- Update the Linux kernel to a release that includes the upstream fix for CVE-2026-98813 (fixed version unknown in the sources)
- Reboot after the kernel update so the fixed kernel is running

## Timeline

- 2026-10-23T21:57:17+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-98813

## From the sources

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

bpf: Hold map BTF for the memory allocator destructor record

bpf_ma_set_dtor() duplicates map->record so that the bpf_mem_alloc
destructor can release the special fields of hash and rhash map elements
once the allocator frees them for good. btf_record_dup() only acquires
references on kernel and module BTF. Fields whose types live in the map
BTF keep pointing into it: a kptr to a local type refers to map->btf,
and a list_head or rb_root field carries a value_rec owned by the struct
meta table of map->btf.

That borrowed state can outlive the map. When RCU callbacks are still in
flight, bpf_mem_alloc_destroy() copies the allocator and defers the final
drain, together with the destructor context, to a workqueue.
bpf_map_free() then frees map->record and drops the map's BTF reference
as soon as map_free() returns. Once the program that loaded the BTF is
gone as well, the BTF is freed while the worker still uses the
duplicate. The worker dereferences it through btf_is_kernel() and
btf_find_struct_meta() in bpf_obj_free_fields() when destroying elements
that were freed under RCU, and through btf_is_kernel() in
btf_record_free() when releasing the context itself:

  BUG: KASAN: slab-use-after-free in btf_is_kernel+0x19/0x30
  Read of size 1 at addr ffff88811505dce8 by task kworker/u16:2/50
  Workqueue: events_unbound free_mem_alloc_deferred
  Call Trace:
   btf_is_kernel+0x19/0x30
   btf_record_free+0xc7/0xf0
   htab_dtor_ctx_free+0x1a/0x30
   free_mem_alloc_no_barrier+0x39/0x230
   free_mem_alloc_deferred+0x2a/0x40
   process_scheduled_works+0x5ce/0x9d0
   worker_thread+0x42a/0x5e0
   kthread+0x1f5/0x230
   ret_from_fork+0x1dd/0x390
   ret_from_fork_asm+0x1a/0x30

  Allocated by task 358:
   __kmalloc_cache_noprof+0x287/0x510
   btf_new_fd+0xf7/0x3d0
   __sys_bpf+0x487/0x840

  Freed by task 0:
   kfree+0x186/0x560
   rcu_core+0x6f6/0xd40

Freeing a map that still holds more elements than the allocator's high
watermark is enough to get there, because the bulk free during teardown
queues the RCU callback that makes bpf_mem_alloc_destroy() defer.
Non-preallocated hash maps and resizable hash maps both register the
destructor and are affected alike.

Keep one reference on the map BTF in the destructor context. Every
non-kernel pointer in the duplicated record is either map->btf or memory
owned by it, so a single reference covers kptrs, list heads, and rb
roots, and mirrors what bpf_map_meta_alloc() does for the duplicated
record of an inner map. Release it only after the duplicated record has
been freed: the worker is preemptible and not in an RCU read-side
critical section, so dropping the last reference first would let the
BTF be freed while btf_record_free() still reads its fields.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
