CVE-2024-53195 - KVM ARM64 Kernel Userspace IRQchip Mismanagement Vulnerability Explained
In June 2024, a significant security issue in the Linux Kernel’s KVM subsystem for ARM64 architectures was resolved. Registered as CVE-2024-53195, this vulnerability could cause system instability under certain conditions—particularly, a kernel warning triggered by improper tracking of a userspace IRQchip. Let’s break down how it happened, why it mattered, and how it was fixed, using plain English and real code examples.
What Is KVM and Why Is This Important?
KVM (Kernel-based Virtual Machine) allows Linux to act as a hypervisor, supporting Linux and Windows virtual machines. On ARM64 (64-bit ARM) processors, KVM emulates hardware features like timers and interrupts for guest operating systems.
Managing virtual interrupts (IRQchip) is tricky: KVM can let userspace (QEMU or similar) manage them or keep it “in-kernel”. This bug involved tracking which mode was used—and what to do if that tracking goes wrong.
What Happened? The Bug, Step by Step
The vulnerability was uncovered by syzbot, the Linux kernel fuzzing bot. Here’s the problematic chain:
A Virtual Machine (VM) and Virtual CPU (vCPU) are created.
2. Userspace issues KVM_ARM_VCPU_INIT requesting a PMU (Performance Monitor Unit) but skips setting up required IRQ infrastructure (like the Virtual Generic Interrupt Controller (vGIC) or the virtual PMU).
Userspace ignores the error, reissues KVM_ARM_VCPU_INIT.
5. On reset, the kernel sees the timer enabled but "forgets" the IRQchip status, leading to an inconsistent state.
A kernel WARN_ON() triggers:
WARNING: CPU: PID: 3281 at arch/arm64/kvm/arch_timer.c:459 kvm_timer_update_irq+x21c/x394
If userspace code is careless (or malicious), this triggers a dangerous kernel warning and possibly causes stability issues.
Code Details: What Was Broken
The bug revolves around improper use of the userspace_irqchip_in_use static key, a kernel optimization tracking whether userspace manages IRQs.
Let’s take a (simplified) look at relevant functions
int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) {
int ret = kvm_arm_pmu_v3_enable(vcpu);
if (ret)
return ret;
// userspace_irqchip_in_use increment *should* happen here, but doesn't on PMU error
if (!irqchip_in_kernel(kvm))
static_branch_inc(&userspace_irqchip_in_use);
// ...
}
void kvm_timer_vcpu_reset(struct arch_timer *timer) {
if (timer->enabled)
kvm_timer_update_irq(timer); // May trigger WARN_ON()
}
The bug: If PMU creation fails, userspace_irqchip_in_use isn’t updated, but the timer is already on. Later, the state mismatches and the kernel hits a code path it never expected.
Here’s what you’d see in dmesg under exploitation
WARNING: CPU: PID: 3281 at arch/arm64/kvm/arch_timer.c:459 kvm_timer_update_irq+x21c/x394
Call trace:
kvm_timer_update_irq+x21c
kvm_timer_vcpu_reset+x158
kvm_reset_vcpu+x3b4
kvm_vcpu_set_target
kvm_arch_vcpu_ioctl_vcpu_init
kvm_arch_vcpu_ioctl
kvm_vcpu_ioctl
...
Exploit Details: How Could This Be Abused?
While this bug is not a classic privilege escalation, it is triggerable from unprivileged userspace with access to /dev/kvm. A malicious or buggy hypervisor (like QEMU or a fuzzing tool) could exploit this by:
A PoC can be written in C (or using QEMU’s API wrappers)
// Pseudocode, not complete error checking for brevity
int fd = open("/dev/kvm", O_RDWR);
int vmfd = ioctl(fd, KVM_CREATE_VM, );
int vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, );
struct kvm_vcpu_init init = { .features = KVM_ARM_VCPU_PMU_V3 };
ioctl(vcpufd, KVM_ARM_VCPU_INIT, &init); // PMU req, but don’t set up vPMU or vGIC
ioctl(vcpufd, KVM_RUN, ); // Fails due to PMU, but enables timer, skips userspace_irqchip_in_use
ioctl(vcpufd, KVM_ARM_VCPU_INIT, &init); // Reset, triggers kvm_timer_vcpu_reset path
// ... Kernel emits warning!
Similar logic can be injected with QEMU device parameters and command-line flags.
The Fix: Simpler, Safer IRQchip Management
The fix is to get rid of the userspace_irqchip_in_use static key and instead rely directly on the function !irqchip_in_kernel() for state checks. This avoids double-counting and mis-tracking, resolving the risk.
Patch Excerpt (Reference: Kernel commit):
- if (!irqchip_in_kernel(kvm))
- static_branch_inc(&userspace_irqchip_in_use);
+ // Now, directly use !irqchip_in_kernel() wherever needed.
No more global static keys to miscount—direct checks for each relevant KVM instance.
- References
- syzkaller bug report
- Linux commit fixing the bug
- KVM ARM64 code
Conclusion
CVE-2024-53195 was a subtle but important flaw that could let a VM user (or an accidental programmer error) make the Linux ARM64 KVM host unstable via improper IRQchip tracking. Thanks to the kernel community’s rapid response, the fix is simple: drop complex global tracking and just check the local state.
Upgrade your kernel if you run virtualization on ARM64 and expose /dev/kvm to untrusted workloads.
Further Reading
- KVM ARM64 Documentation
- KVM API Reference (kernel.org)
- Linux Kernel Security
Timeline
Published on: 12/27/2024 14:15:27 UTC
Last modified on: 05/04/2025 09:55:29 UTC