Skip to content

USB passthrough to VirtualBox on Linux

Louis Maddox edited this page Jun 11, 2021 · 6 revisions

Spoiler: after some investigation it turns out that PCI passthrough (to pass through an entire USB controller) is preferable to per-device passthrough, and this was deprecated in v6.1, so I recommend following this guide with v6.0 rather than 6.1 (or any later version), however on my machine this also wouldn't work, possibly because it requires PCI rather than PCIe. lspci shows my machine uses PCIe (the "root port" lines) which is ultimately what I expect prevents it working, as reported in the changelog. Notes left here in case they help anyone else investigate USB controller passthrough on their own machines.


After installing the VirtualBox extension pack and guest additions I still couldn't get a USB to pass into the VM.

The extension pack is available on the Downloads page of the VirtualBox website.

The guest additions file was an ISO which now ships with VirtualBox, and you can find it on your machine with

find / -iname "VBoxGuestAdditions.iso" 2> /dev/null

in my case it was at /usr/share/virtualbox/VBoxGuestAdditions.iso.

  • To run it click Devices on the VM's toolbar then "Insert Guest Additions CD Image" and select this file.

All that I achieved was to move from USB 1.1 (OHCI) to USB 2.0 (OHCI + EHCI) controller, but this remained greyed out and unchangeable. With the VM powered off these became modifiable, and once changed to USB 3.0 it worked as expected.


When the USB controller was at USB 1.1 or 2.0 rather than 3.0, the error shown in the VM was:

Failed to attach the USB device [USB Device Name Goes Here] to the virtual machine

and this expands to:

Failed to create a proxy device for the USB device (Error: VERR_PDM_NO_USB_PORTS Result code: NS_ERROR_FAILURE (Ox80004005) Component: ConsoleWrap Interface: IConsole ...

I successfully plugged in an iPad USB to an Ubuntu VM, and a plain old storage USB to both Ubuntu VM and macOS VM.

However when plugging an iPad into the macOS VM I received a popup in the host (Linux) OS, announcing that

Could not display "afc://00008103-..." Error: No such interface "org.gtk.vfs.Mount" on object at path /org/gtk/vfs/mount/1 Please select another viewer and try again.

If this is done by selecting the device, it shows up once. If a filter is created to target the iPad, it loops into trying to connect and then dropping it back to the host repeatedly, with the result that many popups are created.

Another popup also appears:

The folder contents could not be displayed. No such interface "org.gtk.vfs.Mount" on object at path /org/gtk/vfs/mount/1

This sounds similar to the reported behaviour on a QEMU/KVM alternative to VirtualBox, on StackOverflow here

  • The question mentions two commands: lsusb on the Linux host and ioreg -p IOUSB on the macOS guest

I verified the same behaviour is seen for my setup, but rather than "a few seconds", I see the device appear for less than 0.2 seconds, using the following command to log to the terminal and then break the loop and review as soon as I see it change:

for i in {1..1000}; do clear; echo $i; lsusb; sleep 0.2; done

It only disappeared once, at the 24th time step (other names and all IDs are removed here):

23
Bus 002 Device 002: ID ... SD
Bus 002 Device 001: ID ... LF
Bus 001 Device 003: ID ... LU
Bus 001 Device 002: ID ... GL
Bus 001 Device 034: ID 05ac:12ab Apple, Inc. iPad 4/Mini1
Bus 001 Device 004: ID ... AC
Bus 001 Device 001: ID ... LF2
24
Bus 002 Device 002: ID ... SD
Bus 002 Device 001: ID ... LF
Bus 001 Device 003: ID ... LU
Bus 001 Device 002: ID ... GL
Bus 001 Device 004: ID ... AC
Bus 001 Device 001: ID ... LF2
25
Bus 002 Device 002: ID ... SD
Bus 002 Device 001: ID ... LF
Bus 001 Device 003: ID ... LU
Bus 001 Device 002: ID ... GL
Bus 001 Device 035: ID 05ac:12ab Apple, Inc. iPad 4/Mini1
Bus 001 Device 004: ID ... AC
Bus 001 Device 001: ID ... LF2

Note:

  • the iPad's device number increments from 034 to 035
  • the device ID remains "05ac:12ab"

While this took place, I left dmesg -w running [on the Linux host] and could see this device number registered upon trying to attach the iPad to the VM:

[136350.933660] ipheth 1-4:4.2: Apple iPhone USB Ethernet now disconnected
[136351.165629] usb 1-4: reset high-speed USB device number 34 using xhci_hcd
[136351.345692] usb 1-4: USB disconnect, device number 34
[136351.785536] usb 1-4: new high-speed USB device number 35 using xhci_hcd
[136351.937974] usb 1-4: New USB device found, idVendor=05ac, idProduct=12ab, bcdDevice=13.04
[136351.937976] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[136351.937978] usb 1-4: Product: iPad
[136351.937979] usb 1-4: Manufacturer: Apple Inc.
[136351.937980] usb 1-4: SerialNumber: ...
[136351.965157] ipheth 1-4:4.2: Apple iPhone USB Ethernet device attached
[136351.967413] ipheth 1-4:4.2 ...: renamed from eth0
  • again the serial number and an ID number are removed here
  • xHCI is the controller for USB 3.0, "HCD" stands for host-controller driver

I came across this blog post from 2018 which indicates it has been done successfully.

I realised at this point that I hadn't been able to install the Guest Additions by clicking the menu item under Devices on the VM toolbar, but there was a disk icon on the desktop which when opened showed a .pkg file with what looked like an installer icon. This led to a wizard which then failed, Apple showing a "System Extension Blocked" message.

After allowing this software in the macOS system settings a system restart was initiated, which somehow reopened all the same windows... but this time the message remained "the installation failed" with no further info.

A Q&A here says that Big Sur in fact cannot install guest additions. This leaves the open question of whether installing the guest additions to the VM before upgrading the VM would have allowed both to coexist... Since in this case the VM was upgraded from Mojave

...upon retrying after installing the guest additions on a Mojave VM, before upgrading to Big Sur, I found I still could not get it to register the iPad on a macOS guest without dropping it back to the host.

I also tried to find and kill gphoto2 processes because of the line in the dmesg -w output about gphoto2 and the interface 0 being claimed, but this didn't work

pgrep -fla gphoto2
112162 /usr/libexec/gvfs-gphoto2-volume-monitor
112170 /usr/libexec/gvfsd-gphoto2 --spawner :1.6 /org/gtk/gvfs/exec_spaw/81

Followed by pkill -f gphoto2. The processes just get recreated (because there's an underlying service no doubt).

To stop the service you'd use:

systemctl --user stop gvfs-afc-volume-monitor.service gvfs-gphoto2-volume-monitor.service gvfs-mtp-volume-monitor.service

After running this, plugging in the iPad no longer brings up the automatic opening of the device as a device containing pictures, and it no longer shows up in the Linux host as a storage drive. The dmesg -w output shows there was a successful registration of the device however.

Now, adding a filter to the VM and adding the device will put it back into the loop of connecting and disconnecting (as shown in dmesg -w output) but there are no longer the Nemo file explorer windows opened each time it does so

  • Trying to remove the device will not work as it is in the middle of reconnecting each time, so instead you should remove the filter to disconnect it from the VM and break out of this loop.

(Side note)

The following would disable them at boot, but I wouldn't recommend changing this:

systemctl --user disable gvfs-afc-volume-monitor.service gvfs-gphoto2-volume-monitor.service gvfs-mtp-volume-monitor.service

One further suggestion [I didn't expect to work] was to chown the file (user/group). I read elsewhere you should use udev rules not ownership, but since the files themselves were temporary I thought it couldn't hurt.

sudo chown louis:louis /dev/bus/usb/001/093

changed the ownership of the device ID of the iPad, but the same result (looping in and out, incrementing the device ID each time) was still seen.

udev rules are used to set persistent device permissions (as in, persisting for the same device even though its device number is changing each time).

There's another suggestion in this thread to

systemctl --user stop gvfs* 

This in fact will make any USB disappear as if ejected... it seems a bit chaotic

The error seems to come down to the fact (according to this) that

"you are trying to attach directly a USB device to your VirtualBox when it's already being used by the host OS"

In other words, ejecting the USB device manually in some way would free it up for use by the guest VM.

Running systemctl status usbmuxd.service shows the daemon is active when the device is plugged in, and inactive (dead) when not plugged in.

Running sudo apt show usbmuxd explains

 This package includes udev rules to start the daemon when a supported
 device is plugged in, and stop it when all devices are removed.

So the outline is: when iPad is plugged in over USB, a udev rule (probably named usbmuxd.rules) initiates the usbmuxd daemon, and stops it when unplugged.

Searching for such a file (find / -iname *usbmuxd.rules 2> /dev/null) brings up one file:

/usr/lib/udev/rules.d/39-usbmuxd.rules

Which is quite simple

# usbmuxd (Apple Mobile Device Muxer listening on /var/run/usbmuxd)

# systemd should receive all events relating to device
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", TAG+="systemd"

# Initialize iOS devices into "deactivated" USB configuration state and activate usbmuxd
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="add",
ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux",
ENV{SYSTEMD_WANTS}="usbmuxd.service"

# Make sure properties don't get lost when bind action is called
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*", ACTION=="bind",
ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux", ENV{SYSTEMD_WANTS}="usbmuxd.service"

# Exit usbmuxd when the last device is removed
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*",
ACTION=="remove", RUN+="/usr/sbin/usbmuxd -x"

One simple way to disable it (temporarily, easily fixable if it causes problems) would therefore be to just comment out this file.

  • Edit it with sudo (the file has root permissions)
  • Unplug the iPad USB first so the mounted device isn't "left hanging"
  • Other suggestions online include uninstalling usbmuxd altogether but this seems unnecessary

This time, when plugged in the usbmuxd.service status remained inactive (dead), but the popup still opened to declare a device with photos had just attached (I think from gvfs?)

There was another file in the udev rules, 60-libgphoto2-6.rules, and also commented out, but the popup still appeared and the camera icon (indicating mounting occurred) still showed upon USB connection.

Once again running systemctl --user stop gvfs* prevented this popup, and no camera icon now showed.

This was the closest to indication of no mounted iPad over USB, however lsusb still showed: Bus 001 Device 031: ID 05ac:12ab Apple, Inc. iPad 4/Mini1, and this time attaching and detaching the iPad from the VM not only failed but crashed the VM entirely.

Since that failed I tried uninstalling: sudo apt remove usbmuxd

  • The file I previously edited 39-usbmuxd.rules disappeared
  • Nevertheless, the same loop began and the iPad did not pass through when connected to the VM

I also tried the approach of untrusting all computers ("Reset location & privacy" in Settings) but this didn't stop the USB device appearing in dmesg -w and looping with incrementing device numbers


To pass through an entire USB controller since individual device passthrough didn't work, it'd be better to have multiple controllers and pass through an isolated IOMMU group but my machine only has one USB controller so I can only pass through that.

This should prevent the host "holding on" to the USB device and preventing it from attaching to the guest macOS VM.

One problem is that my keyboard uses a USB link, so I would need to use SSH to control the PCI attachment, detachment, and the starting/stopping of the VM. Thankfully I have another machine I can do this through (but it's not ideal).

The official guide gives the following example:

Once you made sure that the host kernel supports the IOMMU, the next step is to select the PCI card and attach it to the guest. To figure out the list of available PCI devices, use the lspci command. The output will look like this:

01:00.0 VGA compatible controller: ATI Technologies Inc Cedar PRO [Radeon HD 5450]
01:00.1 Audio device: ATI Technologies Inc Manhattan HDMI Audio [Mobility Radeon HD 5000 Series]
02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit
        Ethernet controller (rev 03)
03:00.0 SATA controller: JMicron Technology Corp. JMB362/JMB363 Serial ATA Controller (rev 03)
03:00.1 IDE interface: JMicron Technology Corp. JMB362/JMB363 Serial ATA Controller (rev 03)
06:00.0 VGA compatible controller: nVidia Corporation G86 [GeForce 8500 GT] (rev a1)

The first column is a PCI address (in format bus:device.function). This address could be used to identify the device for further operations. For example, to attach a PCI network controller on the system listed above to the second PCI bus in the guest, as device 5, function 0, use the following command:

VBoxManage modifyvm "VM name" --pciattach 02:00.0@01:05.0

To detach same device, use

VBoxManage modifyvm "VM name" --pcidetach 02:00.0

It's clear that the first part of the 02:00.0@01:05.0 address for attachment comes from the ethernet controller, 02:00.0 Ethernet controller: Realtek... but the second half 01:05.0 seems to be made with no apparent reasoning behind it (just "as device 5, function 0").

The only problem would be if device 5 already existed, then attaching to it would presumably fail.

Unhelpfully, macOS doesn't seem to have an equivalent to lspci. You can use ioreg | grep pci but it doesn't give such clear indication of PCI address (as bus:device.function), or pipe it to less and look at the tree below these lines (by searching /pci and jumping through with n).

In the VM output from ioreg I don't see any 5 in the part I suspect is device so I doubt it'll be a problem to use that.

  • I do see a 1f which seems to correspond to a device on the host (a few of them actually, 1b, 1c, 1d, 1f) so I'm inclined to believe this might be the corresponding part of the address. Linux has no ioreg command to compare output from so I'm guesstimating.

This would mean I could use:

VBoxManage modifyvm "macOS" --pciattach 00:14.0@01:05.0
VBoxManage modifyvm "macOS" --pcidetach 00:14.0

and I could run these over SSH from another machine so that temporary detachment of USB controller would not interfere with entering these commands (so long as the SSH connection was not interrupted).

Noting that modifyvm is not to be used when the VM is running, the full workflow is:

VBoxManage modifyvm "macOS" --pciattach 00:14.0@01:05.0
VBoxManage startvm "macOS"
VBoxManage controlvm "macOS" poweroff
VBoxManage modifyvm "macOS" --pcidetach 00:14.0
  • Note that acpipowerbutton is supposed to be an alternative to poweroff but didn't work for me

It turned out the --pciattach option had been removed in 6.1 (the current version), so I would need to download 6.0!

  • Mentioned here

  • In changelog here:

    "Linux host: Drop PCI passthrough, > the current code is too incomplete" "(cannot handle PCIe devices at all), i.e. not useful enough"

You can uninstall the current VirtualBox and install the old build without losing your VMs (which live in ~/VirtualBox\ VMs/)

  • For Ubuntu 19.10/20.04-based distros the installer is here

Upon first running the VM, I got an error that the implementation of the USB controller was "part of the saved state" and this couldn't be found, so I turned off the USB in the VM's settings and it then booted as normal.

  • I was prompted to install the extension pack, which must match the version of VirtualBox i.e. this
    • Close VirtualBox and then open the extension pack or else 2 VirtualBox windows will open at once

Unfortunately this damages the VM and puts it back to the starting point, so you must reinstall and set the VM up from scratch.

...after reinstalling and setting it up, I then found that the VM would not start with the PCI attached, the session aborted: code NS_ERROR_FAILURE (0x80004005), component SessionMachine, interface ISession

Looking in the logs the specific error was that a "component factory was not found"

Failed to construct 'pciraw'/0!  VERR_SUPDRV_COMPONENT_NOT_FOUND (-3700)

While trying to debug this error I fixed some other potential problems:

  • the chipset must be set to ICH9 (in the VM settings: System -> Motherboard)
  • if the option for "Nested VT-x/AMD-V" is greyed out in System -> Processor then enable it with VBoxManage modifyvm "macOS" --nested-hw-virt on

After further investigation I found the 6.0.24 User Manual PDF

Importantly, this has a paragraph that the 6.0 webpage version lacked:

Note:The PCI passthrough functionality depends on a Linux kernel module which is by default blacklisted. If the functionality should be made available to all users of the system, edit /etc/modprobe.d/blacklist-vboxpci.conf and comment out the last 2 lines.

This seems to explain the error about a "component factory" (the source code for the errors being thrown is here)

So comment out the blacklisted lines, attach and start the VM

sudo vim /etc/modprobe.d/blacklist-vboxpci.conf

Unfortunately the same error occurred

0:00:00.430451 PDM: Failed to construct 'pciraw'/0! VERR_SUPDRV_COMPONENT_NOT_FOUND (-3700) The component factory was not found.

Clone this wiki locally