Introduction
In my last article I implemented a basic harness for the XHCI VirtualBox device. I wasn’t satisfied with the coverage so I kept trying to improve the harness (and made slight changes in the KVM / qemu code) to be able to fuzz both of the fast and slow path at the same time. The code material is available here.
Issues due to the design of VirtualBox devices
Each VirtualBox device has a fast path and a slow path.
The fast path is handled directly in kernel land (ring-0), right after the guest triggers a MMIO or I/O port access. This is the code path executed synchronously during a VM-exit, while the virtual CPU is paused and control is temporarily transferred to the VirtualBox hypervisor.
The slow path, on the other hand, is handled in user land (ring-3), within the VirtualBox device emulation process. Most of the actual device logic (USB transactions, command ring parsing, descriptor handling, etc.) lives here. And until now I was unable to actually reach that part.
Actually the issue is:
- If I want my harness to be reliable I better target the fast path first and if the slow path needs to handle the current fuzz interation content of the request will be handled by the I/O Monitor (IOM) and will be consumed by another ring-3 thread.

Patching qemu and KVM-PT
I patched qemu-nyx and KVM-PT to be able to submit a different cr3 to filter within the fuzzing loop. In qemu I basically just needed to by remove an if statement:
1 | diff --git a/nyx/pt.c b/nyx/pt.c |
In KVM it was pretty easy to patch as well, I just removed some checks:
1 | diff --git a/arch/x86/kvm/vmx/vmx_pt.c b/arch/x86/kvm/vmx/vmx_pt.c |
Adding the fuzzer’s callback to the device struct
To make easier the debugging and the hooking we need to be able to use the fuzzer API wherever we are in the code base, to do so we can add a field to the structure definition of both PDMDEVREGR0 (ring0) and PDMDEVREGR3 (ring3):
1 | // VirtualBox-7.1.8/include/VBox/vmm/pdmdev.h |
Functions interacting with the guest memory
As far as I have read, the XHCI device is only using PDMDevHlpPCIPhysReadMeta and PDMDevHlpPCIPhysReadUser to read data from the L2 memory. From a fuzzing perspective it means we need to hook those two functions to make them process the fuzzy input instead.
THIS ARTCLE IS NOT FINISHED!!