-
Notifications
You must be signed in to change notification settings - Fork 73
Description
Version
7.2.0
Host OS Type
all
Host OS name + version
macOS Sequoia Version 15.6.1 (24G90)
Host Architecture
ARM
Guest OS Type
all
Guest Architecture
ARM
Guest OS name + version
Debian 12.11.0
Component
USB and Serial Ports
What happened?
Recently I've stumbled upon the regression in USB/IP backend. I've confirmed it works with VirtualBox 7.1.12 (released July 15 2025) and is broken on 7.2.0 for Linux (X86-64), Windows (X86-64) and macOS (Apple Silicon) hosts. My main computer is Apple Mac Mini M4 Pro. On macOS I've tested with Windows 11 Arm64, Debian 12 Arm64 and FreeBSD 14.3 Arm64 guests and USB/IP backend doesn't work in any case. Therefore I think it isn't specific to host/guest/arch combination. Direct USB device capture works fine in all cases, so it seems specific to USBProxyDevice-usbip.cpp.
I would expect USB/IP backend to work as it used to work in VirtualBox 7.1.12.
How can we reproduce this?
There is no established open-source solution for USB/IP server on macOS, so a reproduction on this system is a little convoluted. One needs to use a machine (physical or virtual) with Windows or Linux operating system to export USB devices via USB/IP server.
- Linux has built-in support for USB/IP client and server
- Windows has quite popular third-party implementations of USB/IP protocol
I've played with tools above and all have practical applications / support multiple devices of different classes.
There are also custom USB/IP server implementations, used mainly for the emulation of arbitrary devices, but these usually don't support multiple simultaneous connections required by VirtualBox - one thread in VirtualBox is polling for available devices exported by the server and separate threads are used for each imported device to exchange URBs.
For reproduction, only USB/IP server is of interest, because USB/IP client is already implemented by VirtualBox itself. Considering the above conditions, I think it's easiest to reproduce the issue on Windows or Linux where USB/IP server is readily available. Especially on Linux, setup is already described in Setting up USB/IP Support on a Linux System chapter of VirtualBox manual.
As I have unconstrained access only to macOS machine, I've tried to prepare clear reproduction steps based on virtual machines spawned with VirtualBox. Hopefully it can be reproduced in a similar way on any host system (probably besides steps related to VM setup which seem to contain elements specific to Arm64 guests). Initial steps related to VM creation and guest system installation can be performed using GUI as well. I've ported instructions to command line to avoid pasting multiple screenshots.
Machine configuration and guest OS installation
The setup consists of two identical Linux virtual machines VM A and VM B. VM A is used to run USB/IP server with an emulated USB device on a Linux guest. VM B is used to import USB/IP device exported by VM A using USB/IP client built into VirtualBox. Guest system for VM B doesn't matter - for simplicity it's a clone of VM A.
VM_NAME_A="Debian12A"
VM_NAME_B="Debian12B" # VM B will be the clone of VM A
VDI_PATH_A="$HOME/VirtualBox VMs/$VM_NAME_A/$VM_NAME_A.vdi"
# Use Debian 12 Arm64 as the guest OS which is listed by `vboxmanage list ostypes | grep Debian12_arm64`
vboxmanage createvm --name $VM_NAME_A --ostype "Debian12_arm64" --register
# USB controller is necessary to test the capture of USB/IP device to a virtual machine.
vboxmanage modifyvm $VM_NAME_A --memory 4096 --vram 128 --ioapic on --graphicscontroller vmsvga --usb-xhci on --mouse usbtablet --keyboard usb
# virtio-scsi transport may be specific to macOS Apple Silicon.
# Adapt to other platforms or use GUI configurator to create VM.
vboxmanage storagectl $VM_NAME_A --name "VirtioSCSI" --add virtio-scsi --controller VirtIO --bootable on --hostiocache off --portcount 2
vboxmanage createmedium --filename $VDI_PATH_A --size 20480
vboxmanage storageattach $VM_NAME_A --storagectl "VirtioSCSI" --port 0 --device 0 --type hdd --medium $VDI_PATH_A
# Download ISO from the official source and perform unattended install.
curl -L -o debian-12.11.0-arm64-netinst.iso https://cdimage.debian.org/cdimage/archive/12.11.0/arm64/iso-cd/debian-12.11.0-arm64-netinst.iso
vboxmanage unattended install $VM_NAME_A --iso debian-12.11.0-arm64-netinst.iso --user codespace --user-password codespace --admin-password codespace --start-vm headless
# Once the installation is complete and machine rebooted, turn it off.
# To check for restart in headless mode, run `vboxmanage guestproperty enumerate $VM_NAME_A`.
# The output should contain the line: `/VirtualBox/VMInfo/ResetCounter = '1'`.
vboxmanage controlvm $VM_NAME_A poweroff
# Clone machine (the first one will be used to provide USB/IP server from the Linux guest,
# the second one will be used to attach USB/IP exported device using VirtualBox's built-in USB/IP client).
vboxmanage clonevm $VM_NAME_A --name $VM_NAME_B --register
# Setup port forwarding to access machines via ssh in headless mode.
vboxmanage modifyvm $VM_NAME_A --nat-pf1="guestssh,tcp,,2222,,22"
vboxmanage modifyvm $VM_NAME_B --nat-pf1="guestssh,tcp,,2223,,22"
# For the machine additionally forward USB/IP server port
# which will be used for testing built-in USB/IP client in VirtualBox.
# USB/IP server port 3240 on the guest is forwarded to port 3245 on the host.
vboxmanage modifyvm $VM_NAME_A --nat-pf1="guestusbipserver,tcp,,3245,,3240"
# Start both virtual machines.
vboxmanage startvm $VM_NAME_A --type headless
vboxmanage startvm $VM_NAME_B --type headless
# Virtual machines were launched in headless mode without GUI.
# Connect to them via ssh (we previously configured port forwarding).
ssh -p 2222 codespace@localhost
ssh -p 2223 codespace@localhostThe reproducer provided below doesn't require access to physical USB device.
I've managed to leverage USB Gadget framework with a virtual UDC called usbip-vudc to emulate USB device and export it via USB/IP server on Linux.
A documentation about exporting emulated USB Gadget is supplemented with vudc_server_example.sh. ABI for sysfs-platform-usbip-vudc is also available.
VM A
ssh -p 2222 codespace@localhost (password: codespace):
# Run as superuser (most commands below require root acces).
su
# /usr/sbin is not in the path by default (it contains usbip tool installed later).
export PATH=$PATH:/usr/sbin
# Load basic modules to enable support for USB Gadgets.
modprobe udc-core
modprobe libcomposite
# Create a single instance of virtual UDC.
modprobe usbip-vudc num=1
# Load an example gadget module (CDC-ACM) provided by the kernel.
# By default it is bound to the first available UDC.
modprobe g_serial
# Install userspace tool to handle usbip commands.
apt update && apt install usbip
# Run USB/IP daemon on port 3240 (default) in a device mode.
usbipd --tcp-port 3240 --deviceVM B
ssh -p 2223 codespace@localhost (password: codespace):
su
dmesg -wH
# You will see kernel logs appearing when device gets enumerated.On the host
Optional step: Wireshark for observing USB/IP traffic
11.2. Start Wireshark from the command line:
wireshark --interface lo0 -f "tcp port 3245" -d tcp.port==3245,usbip --display-filter 'usbip and !(_ws.col.info == "Device List Request") and !(_ws.col.info == "Device List Response")' -k -S -lDisplay filter is specified to decode traffic as USB/IP protocol and to filter out abundant OP_REQ_DEVLIST<->OP_REP_DEVLIST traffic from the VirtualBox's USB/IP client polling thread.
Attach USB/IP device to VirtualBox
# Register USB/IP server provided by VM A in the previous steps.
vboxmanage usbdevsource add usbipd3245 --backend USBIP --address 127.0.0.1:3245
# Attach USB/IP device exported by USB/IP server.
# Capture URB traffic in [usbmon format](https://docs.kernel.org/usb/usbmon.html) to get extra information about USB traffic besides the one obtained through Wireshark.
vboxmanage controlvm $VM_NAME_B usbattach "usbip://127.0.0.1:3245:usbip-vudc.0" --capturefile $HOME/vbox_usbip_client_attached_linux_usbip_server.pcapAfter attaching, you should observe the successful USB device enumeration on VM B.
root@vbox:/home/codespace# dmesg -wH
[Aug31 17:54] usb 1-3: new high-speed USB device number 4 using xhci_hcd
[ +0.169678] usb 1-3: New USB device found, idVendor=0525, idProduct=a4a7, bcdDevice= 6.01
[ +0.000003] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ +0.000001] usb 1-3: Product: Gadget Serial v2.4
[ +0.000000] usb 1-3: Manufacturer: Linux 6.1.0-38-arm64 with usbip-vudc
[ +0.024737] cdc_acm 1-3:2.0: ttyACM0: USB ACM device
[ +0.000058] usbcore: registered new interface driver cdc_acm
[ +0.000001] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[ +2.542106] usb 1-3: USB disconnect, device number 4Note
Device disconnects after the enumeration, what is an unintended behavior, but it's the issue specific only to USB/IP server on Linux. usbipd-win server doesn't manifest such behavior.
In any case it's not meaningful for the reproducer, as the regression in VirtualBox 7.2.0 prevents the very first packet from succeeding, so it doesn't even reach the enumerated state.
After testing is finished, unregister USB/IP server.
vboxmanage usbdevsource remove usbipd3245Stop Wireshark capture if it was previously started.
Attachments
I attached the following files collected on macOS Apple Silicon host:
VirtualBox 7.1.12:
-
7_1_12_VBox_A.log - VirtualBox logs from VM A
-
7_1_12_VBox_B.log - VirtualBox logs from VM B
-
7_1_12_vbox_usbip_client_attached_linux_usbip_server_as_plain_text.txt - packet capture of attached USB device using VirtualBox built-in tracing capabilities exported as a plain text (not available for 7.2.0 below due to a regression)
-
7_1_12_wireshark_usbip_as_plain_text.txt - packet capture of USB/IP traffic between client and server using Wireshark exported as a plain text
-
7_1_12_wireshark_pcap.zip - original capture files in pcap format (plain text formats attached above)
VirtualBox 7.2.0:
- 7_2_0_VBox_A.log - VirtualBox logs from VM A
- 7_2_0_VBox_B.log - VirtualBox logs from VM B
- 7_2_0_wireshark_usbip_as_plain_text.txt - packet capture of USB/IP traffic between client and server using Wireshark exported as a plain text
- 7_2_0_wireshark_usbip.pcapng.zip - original capture files in pcap format (plain text formats attached above)
To analyze USB/IP pcap capture files attached in zip archives with wireshark, run the following command to apply the same decoder and filter used during capture:
wireshark -d tcp.port==3245,usbip --display-filter 'usbip and !(_ws.col.info == "Device List Request") and !(_ws.col.info == "Device List Response")' 7_2_0_wireshark_usbip.pcapngAs an alternative, I attached plain text versions of capture files (File -> Export Packet Dissections -> As Plain Text...).
7_2_0_wireshark_usbip_as_plain_text.txt contains especially useful information. It presents 6 consecutive failed attempts to perform a control transfer. The issue seems to arise from USBProxyDevice.cpp::*GetStdDescSync even before XHCI controller kicks in.
Setup packet on VirtualBox 7.2.0 contains some garbage data (9083776b01000000) that doesn't represent a standard request.
Setup packet on VirtualBox 7.1.12 (8006000100001200) represents a standard request GET DESCRIPTOR (DEVICE) and I would expect the same on VirtualBox 7.2.0.
Other fields in USBIP_CMD_SUBMIT packet contain valid data. For example Transfer buffer length [bytes]: 18 what is the expected length of USB Device Descriptor.
Control transfer USB/IP traffic on VirtualBox 7.2.0 (regression)
No. Time Source Destination Protocol Length Info
43 3.006046 host 0.0.0 USB 104 Unknown type 83 Request
Frame 43: 104 bytes on wire (832 bits), 104 bytes captured (832 bits) on interface lo0, id 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 49216, Dst Port: 3245, Seq: 41, Ack: 321, Len: 48
USBIP Protocol
Command: OP_CMD_SUBMIT (0x00000001)
Sequence: 1
[Command frame: 43]
[Return frame: 45]
[Devid: 0x00000000]
[.... .... .... .... .... .... .... ...1 = Direction: IN (0x1)]
[.... .... .... .... .... .... .... 0000 = Endpoint: 0x0]
Devid: 0x00000000
.... .... .... .... .... .... .... ...1 = Direction: IN (0x1)
.... .... .... .... .... .... .... 0000 = Endpoint: 0x0
Transfer flags: 0x00000000
Transfer buffer length [bytes]: 18
ISO Start frame: 0
Number of ISO descriptors: 0
Interval: 0
Setup Data: 9083776b01000000
USB URB
Setup Data
bmRequestType: 0x90
bRequest: Unknown (131)
wValue: 0x6b77
wIndex: 1 (0x0001)
wLength: 0
No. Time Source Destination Protocol Length Info
45 3.006844 127.0.0.1 127.0.0.1 USBIP 104 URB Response
Frame 45: 104 bytes on wire (832 bits), 104 bytes captured (832 bits) on interface lo0, id 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 3245, Dst Port: 49216, Seq: 321, Ack: 89, Len: 48
USBIP Protocol
Command: OP_RET_SUBMIT (0x00000003)
Sequence: 1
[Command frame: 43]
[Return frame: 45]
[Devid: 0x00000000]
[.... .... .... .... .... .... .... ...1 = Direction: IN (0x1)]
[.... .... .... .... .... .... .... 0000 = Endpoint: 0x0]
Devid: 0x00000000
.... .... .... .... .... .... .... ...0 = Direction: OUT (0x0)
.... .... .... .... .... .... .... 0000 = Endpoint: 0x0
Status: Broken pipe (-EPIPE) (-32)
Actual length: 0
ISO Start frame: 0
Number of ISO descriptors: 0
ISO error count: 0
Setup Data: 0000000000000000Control transfer USB/IP traffic on VirtualBox 7.1.12 (okay)
No. Time Source Destination Protocol Length Info
48 3.005296 host 0.0.0 USB 104 GET DESCRIPTOR Request DEVICE
Frame 48: 104 bytes on wire (832 bits), 104 bytes captured (832 bits) on interface lo0, id 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 50691, Dst Port: 3245, Seq: 41, Ack: 321, Len: 48
USBIP Protocol
Command: OP_CMD_SUBMIT (0x00000001)
Sequence: 1
[Command frame: 48]
[Return frame: 50]
[Devid: 0x00000000]
[.... .... .... .... .... .... .... ...1 = Direction: IN (0x1)]
[.... .... .... .... .... .... .... 0000 = Endpoint: 0x0]
Devid: 0x00000000
.... .... .... .... .... .... .... ...1 = Direction: IN (0x1)
.... .... .... .... .... .... .... 0000 = Endpoint: 0x0
Transfer flags: 0x00000000
Transfer buffer length [bytes]: 18
ISO Start frame: 0
Number of ISO descriptors: 0
Interval: 0
Setup Data: 8006000100001200
USB URB
Setup Data
bmRequestType: 0x80
bRequest: GET DESCRIPTOR (6)
Descriptor Index: 0x00
bDescriptorType: DEVICE (0x01)
Language Id: no language specified (0x0000)
wLength: 18
No. Time Source Destination Protocol Length Info
50 3.006187 0.0.0 host USB 122 GET DESCRIPTOR Response DEVICE
Frame 50: 122 bytes on wire (976 bits), 122 bytes captured (976 bits) on interface lo0, id 0
Null/Loopback
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 3245, Dst Port: 50691, Seq: 321, Ack: 89, Len: 66
USBIP Protocol
Command: OP_RET_SUBMIT (0x00000003)
Sequence: 1
[Command frame: 48]
[Return frame: 50]
[Devid: 0x00000000]
[.... .... .... .... .... .... .... ...1 = Direction: IN (0x1)]
[.... .... .... .... .... .... .... 0000 = Endpoint: 0x0]
Devid: 0x00000000
.... .... .... .... .... .... .... ...0 = Direction: OUT (0x0)
.... .... .... .... .... .... .... 0000 = Endpoint: 0x0
Status: Success (0)
Actual length: 18
ISO Start frame: 0
Number of ISO descriptors: 0
ISO error count: 0
Setup Data: 0000000000000000
USB URB
DEVICE DESCRIPTORI'd be eager to provide more necessary information at your request.
I'm in the process of learning how to build and debug VirtualBox from the source on Apple Silicon macOS
so I might be able to provide more useful insights.
Did you upload all of your necessary log files, screenshots, etc.?
- Yes, I've uploaded all pertinent files to this issue.