[usb-host] Assertion failure in usb_host_ep_update() during USB hotplug/unplug on host passthrough
Host environment
-
Operating system:
Ubuntu24.04 LTS
-
OS/kernel version:
6.12
-
Architecture:
x86
-
QEMU flavor:
qemu-system-x86_64
-
QEMU version:
9.1.0
-
QEMU command line:
./qemu-system-x86_64 -M q35 -m 4096 -enable-kvm -hda win.qcow2 -device qemu-xhci,id=xhci -device usb-host,hostbus=1,hostport=4 ...
Emulated/Virtualized environment
-
Operating system:
Windows 11
-
OS/kernel version:
Windows 11
-
Architecture:
x86
Description of problem
QEMU crashes with an assertion failure in usb_host_ep_update() during host USB device hotplug/unplug events, even on the latest QEMU 9.1.0 build. This happens when the VM is using USB host passthrough via -device usb-host,hostbus=<bus>,hostport=<port>
Note: As per QEMU’s intended design, users are expected to manage USB passthrough devices through QMP commands such as device_del and device_add to ensure proper device removal and reattachment. However, in practical deployment scenarios, it is often not feasible to prevent end users from physically hot-unplugging or hot-plugging USB devices at any time.
Steps to reproduce
- Start the guest VM with USB host passthrough (e.g. a USB mouse or USB thumb drive).
- On the guest VM, make sure the passthrough USB device is detected/loaded properly.
- On the host, physically hot-unplug and replug a USB device (for easy of reproducing the issue, plug in a different USB device, e.g. a USB headset or USB camera) on the same hostport.
Expected result
QEMU should safely ignore or warn about invalid altsetting index or values, continue running (even if device enumeration fails) without asserting which is leading to guest VM crashing.
QEMU should allow the guest USB driver to recover from the unplug/plug event.
Additional information
The assertion comes from this section in hw/usb/host-libusb.c (current line: 899):
if (alt != 0) {
assert(alt < conf->interface[i].num_altsetting);
intf = &conf->interface[i].altsetting[alt];
}
Under certain host/libusb conditions, the descriptor may temporarily report an alt index greater than num_altsetting, likely due to race conditions or mismatching interfaces during device reconfiguration or removal. This results in an abort(), terminating QEMU entirely.
Suggested fix
A defensive fix could replace the assert with a bounds check and warning:
if (alt != 0) {
if (alt >= conf->interface[i].num_altsetting) {
warn_report("Invalid altsetting index %d (max=%d) for interface %d — skipping",
alt, conf->interface[i].num_altsetting - 1, i);
continue;
}
intf = &conf->interface[i].altsetting[alt];
}
Optionally, a trace_usb_host_ep_update_invalid_alt() could be added for debug visibility.