GHSA-2FRC-H2G3-59HW
Vulnerability from github – Published: 2026-10-28 12:31 – Updated: 2026-10-28 12:31In the Linux kernel, the following vulnerability has been resolved:
sched/core: Call wakeup_preempt() for queued tasks during class change
Paul reported recent RCU changes exposed a lost resched where CPU idles with a rcutorture thread waiting while being completely runnable.
Dumping the rq state at the time of idling with runnable tasks showed the following:
rq->next_class = &fair_sched_class rq->nr_running = 1 rq->cfs.h_nr_queued = 0 rq->rt.rt_nr_running = 1
Although the waiting task was an RT task, "rq->next_class" did not point to rt_sched_class and was stuck at the lower priority fair_sched_class.
Inspecting sched_change_end() revealed the following race with __sched_setscheduler() for queued, but non-running tasks:
CPU0 CPU1
==== ====
__schedule()
/*
* rq->donor is a fair task that blocks.
* rq->next_class = &fair_sched_class
*/
rq_lock(rq0)
pick_next_task()
/* nr_running = 0 */
pick_task_fair()
sched_balance_newidle()
raw_spin_rq_unlock(rq0)
rq_lock(rq0)
activate_task(rq0, p)
/* p is a fair task */
rq0->nr_running++;
rq0->cfs.h_nr_queued++;
wakeup_preempt(rq, p)
rq->next_class = &fair_sched_class
resched_curr()
rq_unlock(rq0)
__sched_setscheduler(p)
/* p is moved to SCHED_RR */
task_rq_lock(p)
sched_change_begin()
rq0->cfs.h_nr_queued--;
rq0->rt.rt_nr_running++;
sched_change_end()
/*
* p->on_rq = 1 (ctx->queued)
* but p is not rq->donor
* (!ctx->running) hence
* resched_curr() is and
* rq->next_class upgrade is
* skipped.
*/
task_rq_unlock()
raw_spin_rq_lock(rq0)
/*
* rq->nr_running = 1
* rq->cfs.h_nr_queued = 0
* rq->rt.rt_nr_running = 1
* rq->next_class = &fair_sched_class
*/
if (rq->cfs.h_nr_queued && ...)
/* Above is false */
if (rq_modified_above(this_rq, &fair_sched_class))
/* Also false since rq->next_class is still fair */
/*
* sched_balance_newidle() is considered to
* have failed to pull any fair tasks and no
* other wakeups were detected.
*/
return NULL; /* pick_task_fair() */
pick_task_idle()
return rq->idle;
next = rq->idle;
/* Preemption indicators are lost */
clear_tsk_need_resched(prev);
clear_preempt_need_resched();
rq->curr = rq->idle;
!!! rq->idle switches in with rq->running == 1 but !need_resched() !!!
In simple words, enqueue, followed by a class change of the newly queued task goes unnoticed in rq->next_class indicator and sched_balance_newidle() sees no fair task, nor any higher priority task enqueued.
The above sequence will lead to CPU idling with a runnable task on the CPU.
Call wakeup_preempt() for ctx->queued cases in sched_change_end() to re-evaluate rq->next_class after class change (ENQUEUE_CLASS) and set the NEED_RESCHED indicator accordingly.
Newidle balance will correctly see an enqueue of a higher priority t ---truncated---
{
"affected": [],
"aliases": [
"CVE-2026-99205"
],
"database_specific": {
"cwe_ids": [],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-10-28T11:17:41Z",
"severity": null
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\nsched/core: Call wakeup_preempt() for queued tasks during class change\n\nPaul reported recent RCU changes exposed a lost resched where CPU idles\nwith a rcutorture thread waiting while being completely runnable.\n\nDumping the rq state at the time of idling with runnable tasks showed\nthe following:\n\n rq-\u003enext_class = \u0026fair_sched_class\n rq-\u003enr_running = 1\n rq-\u003ecfs.h_nr_queued = 0\n rq-\u003ert.rt_nr_running = 1\n\nAlthough the waiting task was an RT task, \"rq-\u003enext_class\" did not point\nto rt_sched_class and was stuck at the lower priority fair_sched_class.\n\nInspecting sched_change_end() revealed the following race with\n__sched_setscheduler() for queued, but non-running tasks:\n\n CPU0 CPU1\n ==== ====\n\n __schedule()\n\n /*\n * rq-\u003edonor is a fair task that blocks.\n * rq-\u003enext_class = \u0026fair_sched_class\n */\n\n rq_lock(rq0)\n\n pick_next_task()\n /* nr_running = 0 */\n pick_task_fair()\n sched_balance_newidle()\n raw_spin_rq_unlock(rq0)\n rq_lock(rq0)\n\n activate_task(rq0, p)\n /* p is a fair task */\n rq0-\u003enr_running++;\n rq0-\u003ecfs.h_nr_queued++;\n wakeup_preempt(rq, p)\n rq-\u003enext_class = \u0026fair_sched_class\n resched_curr()\n\n rq_unlock(rq0)\n\n __sched_setscheduler(p)\n /* p is moved to SCHED_RR */\n task_rq_lock(p)\n sched_change_begin()\n\n\t\t\t\t rq0-\u003ecfs.h_nr_queued--;\n\t\t\t\t rq0-\u003ert.rt_nr_running++;\n\n sched_change_end()\n /*\n * p-\u003eon_rq = 1 (ctx-\u003equeued)\n * but p is not rq-\u003edonor\n * (!ctx-\u003erunning) hence\n * resched_curr() is and\n * rq-\u003enext_class upgrade is\n * skipped.\n */\n\n task_rq_unlock()\n\n raw_spin_rq_lock(rq0)\n\n /*\n * rq-\u003enr_running = 1\n * rq-\u003ecfs.h_nr_queued = 0\n * rq-\u003ert.rt_nr_running = 1\n * rq-\u003enext_class = \u0026fair_sched_class\n */\n\n if (rq-\u003ecfs.h_nr_queued \u0026\u0026 ...)\n /* Above is false */\n\n if (rq_modified_above(this_rq, \u0026fair_sched_class))\n /* Also false since rq-\u003enext_class is still fair */\n\n /*\n * sched_balance_newidle() is considered to\n * have failed to pull any fair tasks and no\n * other wakeups were detected.\n */\n return NULL; /* pick_task_fair() */\n\n pick_task_idle()\n return rq-\u003eidle;\n\n next = rq-\u003eidle;\n\n /* Preemption indicators are lost */\n clear_tsk_need_resched(prev);\n clear_preempt_need_resched();\n\n rq-\u003ecurr = rq-\u003eidle;\n\n !!! rq-\u003eidle switches in with rq-\u003erunning == 1 but !need_resched() !!!\n\nIn simple words, enqueue, followed by a class change of the newly queued\ntask goes unnoticed in rq-\u003enext_class indicator and\nsched_balance_newidle() sees no fair task, nor any higher priority task\nenqueued.\n\nThe above sequence will lead to CPU idling with a runnable task on the\nCPU.\n\nCall wakeup_preempt() for ctx-\u003equeued cases in sched_change_end() to\nre-evaluate rq-\u003enext_class after class change (ENQUEUE_CLASS) and set\nthe NEED_RESCHED indicator accordingly.\n\nNewidle balance will correctly see an enqueue of a higher priority\nt\n---truncated---",
"id": "GHSA-2frc-h2g3-59hw",
"modified": "2026-10-28T12:31:08Z",
"published": "2026-10-28T12:31:07Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-99205"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/118a2cf4ced60777a2408001e2b4838fed1cea55"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/ae89744c5ebf299bf55ac7581768fbd9f119a903"
}
],
"schema_version": "1.4.0",
"severity": []
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.