Filter USB devices with udev (and some PHP code)

Dec 23, 2022 by Thibault Debatty | 1670 views

Sysadmin PHP

https://cylab.be/blog/250/filter-usb-devices-with-udev-and-some-php-code

USB devices can be a liability : they can be used to exfiltrate data from a computer or server, to plug a hardware keylogger, or to plant a malware. Hence on a managed computer, USB devices should be filtered and whitelisted. In this blog post we show how this can be achieved thanks to udev, and some PHP code.

Udev is the Linux kernel component responsible for managing devices plugged on the system. When a device is plugged, udev basically perform 2 things: 1/ it creates appropriate entry in /dev and 2/ it executes user defined actions. For example, udev is used to trigger printer configuration when a printer is plugged on a USB port.

Ude rule

Custom udev rules are located in /etc/udev/rules.d/. So we can create a file called /etc/udev/rules.de/01-usb-filter.rule with the following content:

#
# USB devices filtering
# https://cylab.be/blog/250/filter-usb-devices-with-udev-and-some-php-code
#

ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", RUN+="/bin/sh -c '/opt/udev-filter-usb /sys$DEVPATH'"

This rule instructs udev to execute the script /opt/udev-filter-usb when a USB device is plugged (ACTION=="add").

Filtering script

Now we can create the filtering script /opt/udev-filter-usb with the following content:

#! /usr/bin/php
<?php
#
# USB devices filtering
# https://cylab.be/blog/250/filter-usb-devices-with-udev-and-some-php-code
#

$allowed_patterns = [
    # internal kernel USB hub
    '/Linux_.*-generic_xhci-hcd_xHCI_Host_Controller/',
    # USB optical mouse
    '/.*USB_Optical_Mouse/',
    # integrated webcam (in a laptop)
    '/.*Integrated_Webcam.*/',
];

$devpath = $argv[1];
$serial = getenv("ID_SERIAL");
$rule = "DENY";

foreach ($allowed_patterns as $pattern) {
    if (preg_match($pattern, $serial)) {
        $rule = "ALLOW";
        break;
    }
}

file_put_contents(
    "/var/log/udev-filter-usb",
    date("Y-m-d H:i:s") . " : $rule : $devpath : $serial\n",
    FILE_APPEND);

if ($rule != "ALLOW") {
    # uncomment next line to actually block devices
    # make sure you have whitelisted your USB keyboard if you use one!
    # exec("echo 0 > $devpath/authorized");
}

As you can see, this script uses regular expressions to allow (whitelist) only some devices. Don't forget to make the script executable:

sudo chmod +x /opt/udev-filter-usb

Testing

To test, simply plug in a USB device, and check the logs in /var/log/udev-filter-usb:

udev-filter-usb.png

Warning: make sure you reboot at least once, and have your keyboard whitelisted, otherwise you may end up with a unusable box!

Blocking unauthorized devices

Once you have whitelisted your devices, you can uncomment the last line (exec("echo 0 > ...). This line writes a 0 in /sys/devices/.../authorized to effectively block unauthorized devices...

This blog post is licensed under CC BY-SA 4.0

This website uses cookies. More information about the use of cookies is available in the cookies policy.
Accept