CVE-2026-63799
Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
19/07/2026
Last modified:
20/07/2026
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
sched/mmcid: Fix OOB clear_bit when CID is MM_CID_UNSET in fixup path<br />
<br />
In mm_cid_fixup_cpus_to_tasks(), when rq->curr has the target mm and<br />
mm_cid.active is set, the CID is checked with cid_in_transit() before<br />
setting the transition bit. In per-CPU mode a newly forked or exec&#39;d<br />
task can be running with mm_cid.cid == MM_CID_UNSET because CIDs are<br />
assigned lazily on schedule-in. With cid_in_transit() the guard passes<br />
for MM_CID_UNSET (no transit bit), converts it to MM_CID_UNSET |<br />
MM_CID_TRANSIT and stores it back; later mm_cid_schedout() feeds this<br />
to clear_bit() with MM_CID_UNSET as the bit number, triggering an<br />
out-of-bounds write.<br />
<br />
Symptoms: this is genuine memory corruption, but a bounded out-of-bounds<br />
write, not an arbitrary one. MM_CID_UNSET is the fixed sentinel BIT(31),<br />
so once the bad value reaches mm_cid_schedout() the cid_from_transit_cid()<br />
strip leaves MM_CID_UNSET, which fails the "cid clear_bit(MM_CID_UNSET,<br />
mm_cidmask(mm)). The cid bitmap is embedded in the mm_struct slab object<br />
(after cpu_bitmap and mm_cpus_allowed) and is only num_possible_cpus()<br />
bits wide, so clearing bit 31 is a deterministic OOB bit-clear at a<br />
fixed offset of 2^31 / 8 == 256 MiB past the bitmap base. The address is<br />
not attacker-influenced (fixed sentinel -> fixed offset) and the op only<br />
clears a single bit; what sits 256 MiB further along the direct map is<br />
whatever kernel object happens to live there, so this corrupts one bit of<br />
unpredictable kernel memory -- it is not an arbitrary-address or<br />
arbitrary-value write.<br />
<br />
It triggers only in per-CPU CID mode, when a CPU is running an active<br />
task of the target mm whose cid is still MM_CID_UNSET -- the<br />
fork()/execve() window before that task&#39;s next schedule-in assigns it a<br />
real CID -- and a per-CPU -> per-task fixup walks over it (the mode<br />
fallback driven by a thread exit, sched_mm_cid_exit(), or by the deferred<br />
max_cids recompute in mm_cid_work_fn()).<br />
<br />
In practice syzkaller surfaced it as a KASAN use-after-free reported in<br />
__schedule -> mm_cid_switch_to, where the offending clear_bit() is inlined<br />
via mm_cid_schedout() -> mm_drop_cid().<br />
<br />
Guard the transition-bit assignment against MM_CID_UNSET, in addition to<br />
the existing cid_in_transit() check, so the bit is only set on a genuine<br />
task-owned CID. A CPU-owned (MM_CID_ONCPU) CID of a running active task<br />
is handled by the cid_on_cpu(pcp->cid) branch above and never reaches<br />
this path, so excluding MM_CID_UNSET (and the already-transitioning case)<br />
is sufficient.
Impact
Base Score 3.x
7.80
Severity 3.x
HIGH



