---
id: "CVE-2026-98942"
kind: "vulnerability"
aliases: ["CVE-2026-98942"]
title: "Linux kernel sched_ext: racing BPF programs can read unfilled CPU ID tables"
severity: "unknown"
cvss: null
epss: 0.00198
exploited: false
status: "open"
category: "runtime"
products: []
ecosystems: []
tags: ["bpf", "linux-kernel", "runtime", "sched-ext"]
not_affected_if: ["default-config"]
published_at: "2026-10-23T13:17:15+00:00"
first_seen_at: "2026-10-23T21:57:33+00:00"
updated_at: "2026-10-25T12:38:50+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-98942", "first_seen_at": "2026-10-23T21:57:33+00:00"}, {"source": "epss", "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-98942", "first_seen_at": "2026-10-25T12:38:50+00:00"}]
---

# Linux kernel sched_ext: racing BPF programs can read unfilled CPU ID tables

The sched_ext scheduler published its CPU ID mapping tables before filling them, so BPF programs calling the cid kfuncs could read uninitialized kernel memory or torn topology data. The fix builds the tables privately and publishes them with RCU.

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

## How to check

- unknown

## Fix

- unknown

## Timeline

- 2026-10-23T21:57:33+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-98942
- 2026-10-25T12:38:50+00:00 epss https://api.first.org/data/v1/epss?cve=CVE-2026-98942

## From the sources

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

sched_ext: Build the cid tables privately and publish them with RCU

The cid tables are visible to the cid kfuncs while being modified: the
first enable publishes the global pointers before filling them,
ops.init_cids() overrides rewrite them in place, and re-enables rebuild
them in place. A racing TRACING or SYSCALL program can read unfilled
entries, including uninitialized memory in the kmalloc'd tables, or torn
topo updates.

Tie the tables' lifetimes to the root sched instead: each root enable
builds a fresh set privately and publishes the per-table __rcu globals once
the layout is final, and root disable unpublishes and RCU-frees the set. A
non-NULL global is now always a fully built table which stays valid for the
reader's RCU read section, and lookups stay two loads. Kfuncs treat NULL as
no-mapping, also after the scheduler exits instead of reporting the stale
last mapping.

The cid kfuncs are available whether the root scheduler is cid-form or
cpu-form, the latter to allow gradual migration to cids. Every root
therefore builds and publishes a default mapping.

Every reader must either be gated on scheduler liveness or NULL-check
inside an RCU read section. Fix the two kfuncs that were neither:
scx_bpf_this_cid() read the table with no RCU or preemption protection and
scx_bpf_task_cid() relied on KF_RCU, which doesn't put a sleepable program
in an RCU read section. The hotplug callbacks are instead serialized by
retiring the tables inside the cpus_read_lock() section that clears
scx_root.

v2: Document why every root builds the tables (desc + cid.c comment).

---

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