Skip to content

USBGuard

USBGuard

How to protect Linux against rogue USB devices using USBGuard

You deployed a perfect firewall and other network security policies preventing unauthorized access to the user’s desktop computer over a network. However, you still need to block USB device access. We can configure a Linux desktop security policy to protect your computer against rogue USB devices (a.k.a. BadUSB) by implementing essential allow and blocklisting capabilities based on device attributes. For instance, I can define what kind of USB devices are authorized and how a USB device interacts with the Linux system. For example, I can define policy allowing Yubikey with serial number “XYZ” and USB LTE modem with serial # “ABC.” Every other USB device access is denied by default.

Installing the USBGuard and other utilities

Info

USBGuard only works on Linux, and the following tutorial will not work with other operating systems such as *BSD or macOS.

We need to install USBGuard as follows:

sudo apt install usbguard usbutils udisks2
Centos
sudo yum install usbguard

Controlling the usbguard service

Use the systemctl command to configure the usbguard service at boot time or restart it when you apply new policy. The syntax is:

sudo systemctl enable usbguard.service --now
sudo systemctl start usbguard.service
sudo systemctl stop usbguard.service
sudo systemctl restart usbguard.service
sudo systemctl status usbguard.service

Listing current USB devices

Use the lsusb command or usb-devices command for displaying information about USB buses in the system and the devices connected to them. For example:

sudo lsusb
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
sudo usb-devices
T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12   MxCh= 0
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1d6b ProdID=0001 Rev=06.08
S:  Manufacturer=Linux 6.8.0-56-generic uhci_hcd
S:  Product=UHCI Host Controller
S:  SerialNumber=0000:00:01.2
C:  #Ifs= 0 Cfg#= 0 Atr= MxPwr=
/usr/bin/usb-devices: 89: cannot open /sys/bus/usb/devices/usb1/1-*:?.*/bInterfaceNumber: No such file
/usr/bin/usb-devices: 90: cannot open /sys/bus/usb/devices/usb1/1-*:?.*/bAlternateSetting: No such file
/usr/bin/usb-devices: 91: cannot open /sys/bus/usb/devices/usb1/1-*:?.*/bNumEndpoints: No such file
/usr/bin/usb-devices: 92: cannot open /sys/bus/usb/devices/usb1/1-*:?.*/bInterfaceClass: No such file
/usr/bin/usb-devices: 93: cannot open /sys/bus/usb/devices/usb1/1-*:?.*/bInterfaceSubClass: No such file
/usr/bin/usb-devices: 94: cannot open /sys/bus/usb/devices/usb1/1-*:?.*/bInterfaceProtocol: No such file
/usr/bin/usb-devices: 103: printf: 0x: not completely converted
/usr/bin/usb-devices: 103: printf: 0x: not completely converted
I:  If#= 0 Alt= 0 #EPs= 0 Cls=() Sub= Prot= Driver=(none)

Rule types

There are three types of target rules for each USB device:

  • allow – Authorize the USB device.
  • block – Do not authorize the USB device, but the system can still see (visible) the device using the lsusb command. However, users can not use the USB device as it remains blocked until the sysadmin authorizes it. (block the device)
  • reject – Do not authorize the USB device, and the device is not visible to the system or users. The USB device needs to be re-inserted again to become visible again. (reject the device)

Understanding /etc/usbguard/usbguard-daemon.conf

The usbguard service reads its default and options from a file named /etc/usbguard/usbguard-daemon.conf:

sudo cat /etc/usbguard/usbguard-daemon.conf
sudo grep -vE '^#|^$' /etc/usbguard/usbguard-daemon.conf

Outputs:

RuleFile=/etc/usbguard/rules.conf
RuleFolder=/etc/usbguard/rules.d/
ImplicitPolicyTarget=block
PresentDevicePolicy=apply-policy
PresentControllerPolicy=keep
InsertedDevicePolicy=apply-policy
AuthorizedDefault=none
RestoreControllerDeviceState=false
DeviceManagerBackend=uevent
IPCAllowedUsers=root
IPCAllowedGroups=root plugdev
IPCAccessControlFiles=/etc/usbguard/IPCAccessControl.d/
DeviceRulesWithPort=false
AuditBackend=FileAudit
AuditFilePath=/var/log/usbguard/usbguard-audit.log
HidePII=false

Disable USB devices authorization

/sys/bus/usb/devices/usb1

echo 0 > authorized echo 0 > authorized_default

/etc/usbguard/usbguard-daemon.conf

#
# Rule set file path.
#
# The USBGuard daemon will use this file to load the policy
# rule set from it and to write new rules received via the
# IPC interface.
#
# RuleFile=/path/to/rules.conf
#
RuleFile=/etc/usbguard/rules.conf

#
# Rule set folder path.
#
# The USBGuard daemon will use this folder to load the policy
# rule set from it and to write new rules received via the
# IPC interface. Usually, we set the option to
# /etc/usbguard/rules.d/. The USBGuard daemon is supposed to
# behave like any other standard Linux daemon therefore it
# loads rule files in alpha-numeric order. File names inside
# RuleFolder directory should start with a two-digit number
# prefix indicating the position, in which the rules are
# scanned by the daemon.
#
# RuleFolder=/path/to/rulesfolder/
#
RuleFolder=/etc/usbguard/rules.d/

#
# Implicit policy target.
#
# How to treat devices that don't match any rule in the
# policy. One of:
#
# * allow  - authorize the device
# * block  - block the device
# * reject - remove the device
#
ImplicitPolicyTarget=block

#
# Present device policy.
#
# How to treat devices that are already connected when the
# daemon starts. One of:
#
# * allow        - authorize every present device
# * block        - deauthorize every present device
# * reject       - remove every present device
# * keep         - just sync the internal state and leave it
# * apply-policy - evaluate the ruleset for every present
#                  device
#
#PresentDevicePolicy=apply-policy
PresentDevicePolicy=block

#
# Present controller policy.
#
# How to treat USB controllers that are already connected
# when the daemon starts. One of:
#
# * allow        - authorize every present device
# * block        - deauthorize every present device
# * reject       - remove every present device
# * keep         - just sync the internal state and leave it
# * apply-policy - evaluate the ruleset for every present
#                  device
#
#PresentControllerPolicy=keep
PresentControllerPolicy=block
#
# Inserted device policy.
#
# How to treat USB devices that are already connected
# *after* the daemon starts. One of:
#
# * block        - deauthorize every present device
# * reject       - remove every present device
# * apply-policy - evaluate the ruleset for every present
#                  device
#
#InsertedDevicePolicy=apply-policy
InsertedDevicePolicy=block
#
# Control which devices are authorized by default.
#
# The USBGuard daemon modifies some the default authorization state attributes
# of controller devices. This setting, enables you to define what value the
# default authorization is set to.
#
# * keep         - do not change the authorization state
# * none         - every new device starts out deauthorized
# * all          - every new device starts out authorized
# * internal     - internal devices start out authorized, external devices start
#                  out deauthorized (this requires the ACPI tables to properly
#                  label internal devices, and kernel support)
#
AuthorizedDefault=none

#
# Restore controller device state.
#
# The USBGuard daemon modifies some attributes of controller
# devices like the default authorization state of new child device
# instances. Using this setting, you can control whether the
# daemon will try to restore the attribute values to the state
# before modification on shutdown.
#
# SECURITY CONSIDERATIONS: If set to true, the USB authorization
# policy could be bypassed by performing some sort of attack on the
# daemon (via a local exploit or via a USB device) to make it shutdown
# and restore to the operating-system default state (known to be permissive).
#
RestoreControllerDeviceState=false

#
# Device manager backend
#
# Which device manager backend implementation to use. One of:
#
# * uevent   - Netlink based implementation which uses sysfs to scan for present
#              devices and an uevent netlink socket for receiving USB device
#              related events.
# * umockdev - umockdev based device manager capable of simulating devices based
#              on umockdev-record files. Useful for testing.
#
DeviceManagerBackend=uevent

#!!! WARNING: It's good practice to set at least one of the !!!
#!!!          two options below. If none of them are set,   !!!
#!!!          the daemon will accept IPC connections from   !!!
#!!!          anyone, thus allowing anyone to modify the    !!!
#!!!          rule set and (de)authorize USB devices.       !!!

#
# Users allowed to use the IPC interface.
#
# A space delimited list of usernames that the daemon will
# accept IPC connections from.
#
# IPCAllowedUsers=username1 username2 ...
#
IPCAllowedUsers=root

#
# Groups allowed to use the IPC interface.
#
# A space delimited list of groupnames that the daemon will
# accept IPC connections from.
#
# IPCAllowedGroups=groupname1 groupname2 ...
#
IPCAllowedGroups=root plugdev

#
# IPC access control definition files path.
#
# The files at this location will be interpreted by the USBGuard
# daemon as access control definition files for the IPC interface.
# The (base)name of a file should be in the form:
#
#   [user][:<group>]
#
# where user is either username or UID and group is either groupname or GID.
# IPC access control files should contain lines in the form:
#
#   <section>=[privilege1][,privilege2] ...
#
# This way each file defines who is able to connect to the IPC
# bus and what privileges he has. Note that the IPC access control
# files need to have file permissions set to 0600.
#
IPCAccessControlFiles=/etc/usbguard/IPCAccessControl.d/

#
# Generate device specific rules including the "via-port"
# attribute.
#
# This option modifies the behavior of the allowDevice
# action. When instructed to generate a permanent rule,
# the action can generate a port specific rule. Because
# some systems have unstable port numbering, the generated
# rule might not match the device after rebooting the system.
#
# If set to false, the generated rule will still contain
# the "parent-hash" attribute which also defines an association
# to the parent device. See usbguard-rules.conf(5) for more
# details.
#
DeviceRulesWithPort=false

#
# USBGuard Audit events log backend
#
# One of:
#
# * FileAudit - Log audit events into a file specified by
#               AuditFilePath setting (see below)
# * LinuxAudit - Log audit events using the Linux Audit
#                subsystem (using audit_log_user_message)
#
AuditBackend=FileAudit

#
# USBGuard audit events log file path.
#
AuditFilePath=/var/log/usbguard/usbguard-audit.log

#
# Hides personally identifiable information such as device serial numbers and
# hashes of descriptors (which include the serial number) from audit entries.
#
HidePII=false