VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-45919

CVE-2026-45919

Description

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

sched/rt: Skip currently executing CPU in rto_next_cpu()

CPU0 becomes overloaded when hosting a CPU-bound RT task, a non-CPU-bound RT task, and a CFS task stuck in kernel space. When other CPUs switch from RT to non-RT tasks, RT load balancing (LB) is triggered; with HAVE_RT_PUSH_IPI enabled, they send IPIs to CPU0 to drive the execution of rto_push_irq_work_func. During push_rt_task on CPU0, if next_task->prio < rq->donor->prio, resched_curr() sets NEED_RESCHED and after the push operation completes, CPU0 calls rto_next_cpu(). Since only CPU0 is overloaded in this scenario, rto_next_cpu() should ideally return -1 (no further IPI needed).

However, multiple CPUs invoking tell_cpu_to_push() during LB increments rd->rto_loop_next. Even when rd->rto_cpu is set to -1, the mismatch between rd->rto_loop and rd->rto_loop_next forces rto_next_cpu() to restart its search from -1. With CPU0 remaining overloaded (satisfying rt_nr_migratory && rt_nr_total > 1), it gets reselected, causing CPU0 to queue irq_work to itself and send self-IPIs repeatedly. As long as CPU0 stays overloaded and other CPUs run pull_rt_tasks(), it falls into an infinite self-IPI loop, which triggers a CPU hardlockup due to continuous self-interrupts.

The trigging scenario is as follows:

cpu0 cpu1 cpu2 pull_rt_task tell_cpu_to_push <------------irq_work_queue_on rto_push_irq_work_func push_rt_task resched_curr(rq) pull_rt_task rto_next_cpu tell_cpu_to_push <-------------------------- atomic_inc(rto_loop_next) rd->rto_loop != next rto_next_cpu irq_work_queue_on rto_push_irq_work_func

Fix redundant self-IPI by filtering the initiating CPU in rto_next_cpu(). This solution has been verified to effectively eliminate spurious self-IPIs and prevent CPU hardlockup scenarios.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A Linux kernel RT scheduling flaw causes a CPU to self-IPI in an infinite loop, leading to a hardlockup when CPU0 is overloaded with RT tasks and other CPUs trigger load balancing.

Vulnerability

The vulnerability is a race condition in the Linux kernel's real-time (RT) scheduling load balancing logic, affecting versions that include HAVE_RT_PUSH_IPI (typically CONFIG_HAVE_RT_PUSH_IPI). When CPU0 is overloaded with a mix of CPU-bound RT tasks, non-CPU-bound RT tasks, and a CFS task stuck in kernel space, and other CPUs switch from RT to non-RT tasks, RT load balancing is triggered. The function rto_next_cpu() in kernel/sched/rt.c fails to skip the currently executing CPU, causing CPU0 to repeatedly self-IPI and execute rto_push_irq_work_func in an infinite loop. This leads to a CPU hardlockup [1].

Exploitation

An attacker needs to be able to create processes with real-time scheduling priority (e.g., via sched_setscheduler with SCHED_RR or SCHED_FIFO) on a system with the vulnerable kernel configuration (HAVE_RT_PUSH_IPI). By creating a CPU-bound RT task, a non-CPU-bound RT task, and a CFS task that blocks in kernel space on CPU0, while other CPUs run pull_rt_tasks() during load balancing, the race condition can be triggered. The attacker does not need to have precise timing control; the sequence described in the CVE description shows that multiple CPUs calling tell_cpu_to_push() increments rd->rto_loop_next, causing rto_next_cpu() to reselect CPU0 even when rd->rto_cpu is -1. This results in CPU0 queuing irq_work to itself infinitely [1].

Impact

On successful exploitation, CPU0 enters a hardlockup state due to continuous self-IPIs, causing the system to become unresponsive or crash. This is a denial-of-service (DoS) condition affecting availability. The attacker does not gain elevated privileges or data access, but can cause a system-wide hang or reboot, impacting the operation of the machine [1].

Mitigation

The fix is in the Linux kernel commit a6a73403733e86748421f2eeaf028c85683ef896, which filters the initiating CPU in rto_next_cpu() to prevent redundant self-IPI. This commit has been applied to stable kernel branches (the exact version depends on the distribution backport). Users should update to a kernel version that includes this commit. There is no known workaround beyond disabling HAVE_RT_PUSH_IPI via kernel configuration (not practical for running RT workloads) [1].

AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

16
52aeb1e07ec2

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 6.18.14via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index fb07dcfc60a244..d4d994fb8999a4 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2100,6 +2100,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2123,6 +2124,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
8ad5577b2d4a

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 6.6.128via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 2d0acdd32108ab..0b420a65b31dc9 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2219,6 +2219,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2242,6 +2243,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
a6a73403733e

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 6.12.75via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index c437a150262384..ffcce501ed40c6 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2151,6 +2151,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2174,6 +2175,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
d57d0746276a

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 5.10.252via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 1289991c970e1c..cc6950fc6061e0 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2005,6 +2005,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2028,6 +2029,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
9f25edc5a20c

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 6.19.4via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index f1867fe8e5c535..e0ff909050190b 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2100,6 +2100,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2123,6 +2124,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
3b3c672a66db

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 5.15.202via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 9720b3c19ab97f..c5122e5f258e43 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2068,6 +2068,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2091,6 +2092,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
16ca9f3117e9

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 6.1.165via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 3a2335bc1d58b2..99e5d37b3f6eba 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2230,6 +2230,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2253,6 +2254,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
94894c9c477e

sched/rt: Skip currently executing CPU in rto_next_cpu()

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitChen JinghuangJan 22, 2026Fixed in 7.0via kernel-cna
1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 0a9b2cd6da7208..a7680477fa6f6b 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2106,6 +2106,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2129,6 +2130,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
94894c9c477e

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 0a9b2cd6da7208..a7680477fa6f6b 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2106,6 +2106,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2129,6 +2130,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
9f25edc5a20c

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index f1867fe8e5c535..e0ff909050190b 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2100,6 +2100,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2123,6 +2124,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
a6a73403733e

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index c437a150262384..ffcce501ed40c6 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2151,6 +2151,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2174,6 +2175,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
d57d0746276a

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 1289991c970e1c..cc6950fc6061e0 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2005,6 +2005,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2028,6 +2029,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
16ca9f3117e9

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 3a2335bc1d58b2..99e5d37b3f6eba 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2230,6 +2230,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2253,6 +2254,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
3b3c672a66db

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 9720b3c19ab97f..c5122e5f258e43 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2068,6 +2068,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2091,6 +2092,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
52aeb1e07ec2

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index fb07dcfc60a244..d4d994fb8999a4 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2100,6 +2100,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2123,6 +2124,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    
8ad5577b2d4a

sched/rt: Skip currently executing CPU in rto_next_cpu()

1 file changed · +5 1
  • kernel/sched/rt.c+5 1 modified
    diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
    index 2d0acdd32108ab..0b420a65b31dc9 100644
    --- a/kernel/sched/rt.c
    +++ b/kernel/sched/rt.c
    @@ -2219,6 +2219,7 @@ static void push_rt_tasks(struct rq *rq)
      */
     static int rto_next_cpu(struct root_domain *rd)
     {
    +	int this_cpu = smp_processor_id();
     	int next;
     	int cpu;
     
    @@ -2242,6 +2243,10 @@ static int rto_next_cpu(struct root_domain *rd)
     
     		rd->rto_cpu = cpu;
     
    +		/* Do not send IPI to self */
    +		if (cpu == this_cpu)
    +			continue;
    +
     		if (cpu < nr_cpu_ids)
     			return cpu;
     
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing self-CPU filter in rto_next_cpu() allows the overloaded CPU to select itself for IPI, causing an infinite self-IPI loop."

Attack vector

An attacker who can create a workload where CPU0 hosts a CPU-bound RT task, a non-CPU-bound RT task, and a CFS task stuck in kernel space can trigger the bug. When other CPUs switch from RT to non-RT tasks, RT load balancing (LB) is triggered and, with `HAVE_RT_PUSH_IPI` enabled, they send IPIs to CPU0 via `tell_cpu_to_push()`. Multiple CPUs invoking `tell_cpu_to_push()` increment `rd->rto_loop_next`, causing a mismatch with `rd->rto_loop` that forces `rto_next_cpu()` to restart its search from -1. Since CPU0 remains overloaded (satisfying `rt_nr_migratory && rt_nr_total > 1`), it gets reselected, causing CPU0 to queue `irq_work` to itself and send self-IPIs repeatedly, leading to an infinite self-IPI loop and a CPU hardlockup.

Affected code

The vulnerability resides in the `rto_next_cpu()` function in `kernel/sched/rt.c`. The function iterates over CPUs in the root domain to select a target for RT push IPIs but did not exclude the currently executing CPU from the search.

What the fix does

The patch adds `int this_cpu = smp_processor_id();` at the start of `rto_next_cpu()` and inserts a check `if (cpu == this_cpu) continue;` inside the loop that iterates over candidate CPUs. This prevents the function from selecting the CPU that is currently executing `rto_next_cpu()` as the target for an IPI, thereby eliminating the self-IPI loop. The fix is minimal — it simply skips the local CPU rather than sending an IPI to itself, which was both unnecessary and harmful.

Preconditions

  • configCPU0 must host a CPU-bound RT task, a non-CPU-bound RT task, and a CFS task stuck in kernel space
  • configHAVE_RT_PUSH_IPI must be enabled in the kernel configuration
  • inputOther CPUs must be running pull_rt_tasks() and switching from RT to non-RT tasks

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.