jails Problem accessing USB device from jail

Hello to everyone.

This is my first post to the forums :)

I am trying to make a USB device (XGecu T48) work under FreeBSD inside a 32bit jail (13.2-RELEASE).
For this, I am required to use libusb to communicate with the device.
I can observe that the USB device can be opened in the host system and also on the jail, but I cannot use it in my project.
After much debugging, I found out that the problem is that, after opening the USB device in the jail, the IOCTL for USB_FS_INIT fails.

Here is a small program that I use to test the problem (compile with gcc12 -o test test.c -lusb):
C:
#include <stdio.h>
#include <libusb.h>

int main( void ) {
  libusb_device_handle *device_handle;
  libusb_device **devs = NULL;
  struct libusb_device_descriptor desc;

  libusb_init(NULL);

  for ( int i=0; i<libusb_get_device_list(NULL,&devs); i++ ) {
    if (LIBUSB_SUCCESS != libusb_get_device_descriptor(devs[i], &desc)) break;
    if (0x0a53==desc.idProduct && 0xa466==desc.idVendor) {
      if ( LIBUSB_SUCCESS==libusb_open(devs[i], &device_handle) &&
           LIBUSB_SUCCESS==libusb_claim_interface(device_handle, 0) ) {
        printf("OK to open device\n");
        libusb_close(device_handle);
      } else {
        printf("NOT ok to open device\n");
      }
    }
  }
  return 0;
}

Note: this code probably has some memory leakages, or resource leakages, but that is not the point.
This program just simply searches for the device matching the USB VID and PID, and tries to open it.
Compiling and running this program in the host and in the jail produces different results.

Here is a sample output from truss inside the jail:
Code:
openat(AT_FDCWD,"/dev/ugen1.3",O_RDWR,00)     = 5 (0x5)
openat(AT_FDCWD,"/dev/ugen1.3",O_RDWR,00)     = 6 (0x6)
ioctl(6,USB_GET_PLUGTIME,0x60cbf2dc)         = 0 (0x0)
ioctl(6,USB_FS_INIT,0x2c512320)             ERR#25 'Inappropriate ioctl for device'
close(6)                     = 0 (0x0)
close(5)                     = 0 (0x0)
fstat(1,{ mode=crw--w---- ,inode=484,size=0,blksize=4096 }) = 0 (0x0)
ioctl(1,TIOCGETA,0x2c512208)             = 0 (0x0)
NOT ok to open device
write(1,"NOT ok to open device\n",22)         = 22 (0x16)

And here a sample output, but from the host system:
Code:
openat(AT_FDCWD,"/dev/ugen1.3",O_RDWR,00)     = 5 (0x5)
openat(AT_FDCWD,"/dev/ugen1.3",O_RDWR,00)     = 6 (0x6)
ioctl(6,USB_GET_PLUGTIME,0x60cbf2dc)         = 0 (0x0)
ioctl(6,USB_FS_INIT,0x60cbf2e0)             = 0 (0x0)
write(4,"\0",1)                     = 1 (0x1)
fstat(1,{ mode=crw--w---- ,inode=507,size=0,blksize=4096 }) = 0 (0x0)
ioctl(1,TIOCGETA,0x60cbf170)             = 0 (0x0)
OK to open device
write(1,"OK to open device\n",18)         = 18 (0x12)

Can anyone help me to figure out how to make this USB device work in the FreeBSD jail?
Any help is greatly appreciated.
Thank you.
 
So... I have managed to find the problem, but I do not have a good solution for it but a dirty solution - let me explain.

To debug this problem I have dtrace'd the USB calls to the Kernel.
The dtrace script that I wrote and that can clearly indicate the root-cause for the issue is the following:
Code:
fbt::ugen_ioctl_post:entry
{
  printf("cmd=%x",arg1);
}

I have run this script (including traces to all the other ugen fbt calls - see attachment) both inside the jail and in the host, and also compared the results (right-hand-side is host, left-hand-side is jail):
Screenshot_2023-04-16_16-33-06.png


This means that the IOCTL is called differently inside the 32bit jail and in the host.
The indicated differences are related to the size of the parameter to the USB_FS_INIT IOCTL, which is defined in usb_ioctl.h

Note: the cmd in the right-hand-side can be interpreted as follows: 0x8 008 55 c3.
Here, 0x8 represents IO Write, 0x008 represents the size of struct usb_fs_init, 0x55 represents 'U' in ASCII, and 0xc3 represents 195, as in the definition of USB_FS_INIT: _IOW ('U', 195, struct usb_fs_uninit).

I concluded that, since I am running a 32bit jail in a 64bit machine, the included libusb inside the jail uses/assumes different sizes for the internal data structures (in this case, for struct usb_fs_init).
This difference, in turn, results in different values for USB_FS_INIT for 32bit FreeBSD and 64bit FreeBSD (e.g. int has different size in both platforms).
In conclusion, the file /usr/lib/libusb.so.3 inside the jail cannot handle a 64bit kernel. Note: FreeBSD does not support multiarch.

I managed to solve the problem using a dirty solution.
Although FreeBSD does not support multiarch, it does ship with a 32bit version of libusb for 64bit systems.
Therefore, the (dirty) solution consists of manually copying the file /usr/lib32/libusb.so.3 from the host to replace /usr/lib/libusb.so.3 inside the container.

After doing this, all is well again :)

PS: for completeness, I have followed the following tutorial to create the jail.
 

Attachments

Back
Top