CVE-2024-57949 - Nested Interrupt Bug in Linux Kernel GIC-V3 ITS Fixed

On June 2024, a critical bug (now tracked as CVE-2024-57949) was found and patched in the Linux kernel’s irqchip/gic-v3-its subsystem. This vulnerability could unexpectedly enable interrupts at the wrong time — a subtle but potentially dangerous error for low-level kernel code that controls how the CPU handles hardware events.

This post breaks down the bug, how it happened in code, and how it was fixed. All code references and links point to official sources and provide insight for kernel users, maintainers, and security researchers.


## Background: What's the irqchip/gic-v3-its?

The GICv3 ITS (Interrupt Translation Service) is a part of the ARM Generic Interrupt Controller system, which handles hardware interrupts on newer ARM CPUs (commonly found in servers, phones, TVs, and even cars).

Interrupts must be managed with utmost care in the Linux kernel. If they're enabled or disabled at bad times, serious stability or security issues can result.

The Broken Code Path

This issue centers on the irq_set_vcpu_affinity() API, which assigns a given virtual CPU to handle a particular interrupt.

Let’s look at the call chain that exposed the bug (simplified)

irq_set_vcpu_affinity()
  └─> irq_get_desc_lock()
        └─> raw_spin_lock_irqsave() // disables local CPU interrupts
  └─> its_irq_set_vcpu_affinity()
        └─> guard(raw_spinlock_irq)
            // incorrectly enables interrupts upon exit
  └─> irq_put_desc_unlock()
        // expects interrupts to still be disabled, but they're enabled! Oops.

Control passes to its_irq_set_vcpu_affinity().

- That function once had a raw spinlock; after commit b97e8a2f713, it used guard(raw_spinlock_irq).
- Exiting the guard enables interrupts — but they’re supposed to stay off until irq_put_desc_unlock()! This leads to a mismatch and a kernel warning.

This is a pseudo-code illustration for clarity

void its_irq_set_vcpu_affinity(...) {
    guard(raw_spinlock_irq) lock(g->lock);  // Oops! Enables interrupts when guard ends
    // ... critical section ...
} // <-- Interrupts get enabled here

After (Patched)

The solution: use a plain spinlock without enabling interrupts.

void its_irq_set_vcpu_affinity(...) {
    guard(raw_spinlock) lock(g->lock);  // Correct: does NOT affect interrupt state
    // ... critical section ...
} // <-- Interrupts state stays unchanged

The patch changes guard(raw_spinlock_irq) to guard(raw_spinlock).

Associated patch commit:
torvalds/linux@7106a71b1c92

Potential Exploit Scenario

While this bug is tricky to exploit directly (since it’s a logic flaw, not a buffer overflow), it could theoretically be abused in combined attacks or lead to weird kernel crashes. For example:

Could cause rare, timing-dependent races or security boundary crossings.

No public exploits exist as of June 2024. However, any subsystem which relies on strict interrupt discipline could be destabilized.

How Do I Fix This?

- Upgrade your Linux kernel to a version including the patch (torvalds/linux@7106a71b1c92).

$ uname -a

- If you see kernel warnings about interrupts enabled/disabled in atomic, check your logs (dmesg).

References

- GitHub commit fixing CVE-2024-57949
- Git commit introducing the bug (b97e8a2f713)
- kernel.org Linux stable releases
- NVD CVE-2024-57949

Conclusion

Tiny mistakes in kernel-level locking can have big consequences. CVE-2024-57949 is a good reminder: never enable interrupts just because a code pattern *looks* correct — always match your locking and interrupt discipline, especially in low-level code.

Patch now if you run Linux on ARM servers or critical systems!

If you want to learn more about how the kernel handles locking and IRQs, check out the Linux Kernel Locking guide.

Timeline

Published on: 02/09/2025 12:15:28 UTC
Last modified on: 02/11/2025 16:06:53 UTC