USB – How to Use Only Mass Storage Devices on a Selected USB Port

driversudevusb

On a given USB port, I only want to accept USB Mass Storage capabilities, and nothing else. No HID devices, no Bluetooth adapters, no RS232 converters, nothing. Is there a way to do this e.g. using udev? I'm aware that I can write a custom udev rule for including a driver for a given device, or a given port, but can I somehow exclude all other drivers? I'm trying to only allow one class of devices, namely USB Mass Storage; there are a myriad different device models in this class, and I don't know which are going to connect to the port (clients will bring their own, there is no way for me to affect this).

Threats from reprogrammed USB firmware are only going to get worse in the foreseeable future. I'm trying to mitigate them for this use case: I have a computer with internally connected USB peripherals (network card, specialized peripherals, keyboard) and one public-facing USB port, which is only supposed to be used for file transfer. So, I can't blacklist the other USB modules altogether; but I'd like to "sanitize" that particular port, so that plugging in a different device type would do nothing.

The case is physically locked, so that only this one specific USB port is accessible from outside, and meddling with the case or splicing into the keyboard cable should be suspicious enough to trigger physical security response; moreover, I don't expect most of the users to be actively malicious, but I expect the number of unwitting carriers of re-flashed USB drives to increase (as it was with floppy boot sector infections of yore). As far as security goes, it does not really matter whether the user brings the "weaponized" USB disk with malicious intent, or just doesn't know that it's "infected".

I am aware that perfect security is infeasible here, and allowing user to interact with the system in any way is risky – but alas, I need to balance security against usability: the computer needs to be client-usable. Also, I'm not trying to defend against a targetted, determined attacker with this; rather, I'm using this as one of mitigation techniques, so that the system is not low-hanging-fruit.

Best Answer

It seems to work for me in Ubuntu 14.04 with 2 flash keys & android phone as storage and usb network adapter & webcam as other type. (I couldn't test placing a usb hub)

  1. Check USB port (which is a parent device for the plugged device)

    $ udevadm info --name=/dev/sdc --attribute-walk
    
      looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0':
        KERNELS=="2-1.2:1.0"
        SUBSYSTEMS=="usb"
        DRIVERS=="usb-storage"
        ATTRS{bInterfaceClass}=="08"
        ATTRS{bInterfaceSubClass}=="06"
        ATTRS{bInterfaceProtocol}=="50"
        ATTRS{bNumEndpoints}=="02"
        ATTRS{supports_autosuspend}=="1"
        ATTRS{bAlternateSetting}==" 0"
        ATTRS{bInterfaceNumber}=="00"
    
  2. Create udev rule, matching usb port kernel name without usb-storage driver

    /etc/udev/rules.d/90-remove-non-storage.rules

    Allow any device that have storage as 1st interface (Composite devices allowed)

    KERNELS=="2-1.2:1.0", DRIVERS!="usb-storage", RUN+="/bin/sh -c 'echo 1 > /sys/bus/usb/drivers/hub/2-1\:1.0/port2/device/remove'"
    

    Block any device that have a non storage interface (Composite devices denied)

    Actually, Phone gets mounted as modem to /dev/ttyACM0 as KERNELS=="2-1.2:1.1". This will not let phones (composite devices) to be mount only simple storage devices will.

    KERNELS=="2-1.2:1.[0-9]*", DRIVERS!="usb-storage", RUN+="/bin/sh -c 'echo 1 > /sys/bus/usb/drivers/hub/2-1\:1.0/port2/device/remove'"
    

    Block only interfaces that are not storage (Composite devices allowed as storage only)

    After some search about a way to disable only non allowed interfaces. Driver unbinding seems to work. My phone could only be used as storage, It does not create /dev/ttyACM0.

    KERNELS=="2-1.2:1.[0-9]*", DRIVERS!="usb-storage", RUN+="/bin/sh -c 'echo -n %k >/sys%p/driver/unbind'"
    
  3. Reload udev rules

    udevadm control --reload-rules
    

References:

Related Question