7.6 KiB
USB Hardening
Qubes OS provides means to attach USB devices to a qube and in general recommends using an USB qube. The Qubes OS documentation also highlights the security implications.
Nonetheless users may want to
- harden their qubes with attached USB devices against USB attacks.
- harden
dom0
against USB attacks, if they assigned some USB ports todom0
, e.g. for USB keyboard or mice to avoid the security pitfalls of assigning them to an USB qube.
USBGuard is a tool that can be used for such purposes.
USBGuard
Security Considerations
By default the Linux kernel will attempt to recognize plugged in USB devices based on their device ID
and load the kernel drivers matching that device ID. If e.g. those device drivers have security issues,
an attacker can exploit those and take control of the qube or in the case of dom0
the entire system.
USBGuard uses kernel interfaces to whitelist USB devices based on their provided interfaces and device IDs. Keep in mind though that rogue USB devices can easily forge device IDs and/or launch a brute-force attack on an unknown whitelisted device ID.
Rogue devices however cannot exploit interfaces/kernel drivers that are not made available to them due to USBGuard. This is where hardening may make sense.
Installation
USBGuard should be available from the default repositories of your Qubes templates.
For dom0, you can install it via
sudo qubes-dom0-update usbguard
The usual security considerations for
software installations in dom0
apply.
dom0
Example Setup
(The below guide only works with Qubes OS 4.1 or higher.)
The below setup is intended for users with USB ports that are connected to dom0
. It doesn't whitelist
any devices (users may want to add their device/interface combinations for convenience), but assumes the
following:
- All USB devices attached at boot time are allowed, all others rejected.
- The user may employ a small script to allow USB devices attached during the next minute or so. Only certain reasonable USB device classes (audio, HID, mass storage, hub, smart card) are allowed.
USBGuard Configuration
To achieve that, edit the USBGuard configuration at /etc/usbguard/usbguard-daemon.conf
to include the
following lines:
#reject all devices by default
ImplicitPolicyTarget=reject
#allow all devices that are available at boot time
PresentDevicePolicy=allow
PresentControllerPolicy=allow
The policy itself at /etc/usbguard/rules.conf
would have to look as follows:
############ REJECT #################
#only let certain interfaces pass to our default policy and block all others
#generate via bash: seq 0 255 | while read -r i ; do printf '%.2X:*:* ' "$i" ; done
#NOTE: reject *:* with-interface none-of { allowed ones } wouldn't work precisely as a malicious device could just add an interface of the allowed types _in addition_ to its unwanted interface types to pass
#
#only allowed:
#01: audio
#03: HID
#08: mass storage
#09: hub
#0B: smart card
reject *:* with-interface one-of { 00:*:* 02:*:* 04:*:* 05:*:* 06:*:* 07:*:* 0A:*:* 0C:*:* 0D:*:* 0E:*:* 0F:*:* 10:*:* 11:*:* 12:*:* 13:*:* 14:*:* 15:*:* 16:*:* 17:*:* 18:*:* 19:*:* 1A:*:* 1B:*:* 1C:*:* 1D:*:* 1E:*:* 1F:*:* 20:*:* 21:*:* 22:*:* 23:*:* 24:*:* 25:*:* 26:*:* 27:*:* 28:*:* 29:*:* 2A:*:* 2B:*:* 2C:*:* 2D:*:* 2E:*:* 2F:*:* 30:*:* 31:*:* 32:*:* 33:*:* 34:*:* 35:*:* 36:*:* 37:*:* 38:*:* 39:*:* 3A:*:* 3B:*:* 3C:*:* 3D:*:* 3E:*:* 3F:*:* 40:*:* 41:*:* 42:*:* 43:*:* 44:*:* 45:*:* 46:*:* 47:*:* 48:*:* 49:*:* 4A:*:* 4B:*:* 4C:*:* 4D:*:* 4E:*:* 4F:*:* 50:*:* 51:*:* 52:*:* 53:*:* 54:*:* 55:*:* 56:*:* 57:*:* 58:*:* 59:*:* 5A:*:* 5B:*:* 5C:*:* 5D:*:* 5E:*:* 5F:*:* 60:*:* 61:*:* 62:*:* 63:*:* 64:*:* 65:*:* 66:*:* 67:*:* 68:*:* 69:*:* 6A:*:* 6B:*:* 6C:*:* 6D:*:* 6E:*:* 6F:*:* 70:*:* 71:*:* 72:*:* 73:*:* 74:*:* 75:*:* 76:*:* 77:*:* 78:*:* 79:*:* 7A:*:* 7B:*:* 7C:*:* 7D:*:* 7E:*:* 7F:*:* 80:*:* 81:*:* 82:*:* 83:*:* 84:*:* 85:*:* 86:*:* 87:*:* 88:*:* 89:*:* 8A:*:* 8B:*:* 8C:*:* 8D:*:* 8E:*:* 8F:*:* 90:*:* 91:*:* 92:*:* 93:*:* 94:*:* 95:*:* 96:*:* 97:*:* 98:*:* 99:*:* 9A:*:* 9B:*:* 9C:*:* 9D:*:* 9E:*:* 9F:*:* A0:*:* A1:*:* A2:*:* A3:*:* A4:*:* A5:*:* A6:*:* A7:*:* A8:*:* A9:*:* AA:*:* AB:*:* AC:*:* AD:*:* AE:*:* AF:*:* B0:*:* B1:*:* B2:*:* B3:*:* B4:*:* B5:*:* B6:*:* B7:*:* B8:*:* B9:*:* BA:*:* BB:*:* BC:*:* BD:*:* BE:*:* BF:*:* C0:*:* C1:*:* C2:*:* C3:*:* C4:*:* C5:*:* C6:*:* C7:*:* C8:*:* C9:*:* CA:*:* CB:*:* CC:*:* CD:*:* CE:*:* CF:*:* D0:*:* D1:*:* D2:*:* D3:*:* D4:*:* D5:*:* D6:*:* D7:*:* D8:*:* D9:*:* DA:*:* DB:*:* DC:*:* DD:*:* DE:*:* DF:*:* E0:*:* E1:*:* E2:*:* E3:*:* E4:*:* E5:*:* E6:*:* E7:*:* E8:*:* E9:*:* EA:*:* EB:*:* EC:*:* ED:*:* EE:*:* EF:*:* F0:*:* F1:*:* F2:*:* F3:*:* F4:*:* F5:*:* F6:*:* F7:*:* F8:*:* F9:*:* FA:*:* FB:*:* FC:*:* FD:*:* FE:*:* FF:*:* }
############# ALLOW ################
# You may want to add your devices here for convenience, but it's not absolutely necessary if you use the provided script to temporarily allow new devices.
#NOTE: the one-ofs are workarounds for https://github.com/USBGuard/usbguard/issues/207
# Since we filter out everything else above, one-of should be fine.
#USB hubs (some internal)
#allow id xxxx:xxxx with-interface one-of { 09:*:* }
#mouse & keyboard
#allow id xxxx:xxxx with-interface one-of { 03:*:* }
#external sound card
#allow id xxxx:xxxx with-interface one-of { 01:*:* }
#hard disks
#allow id xxxx:xxxx with-interface one-of { 08:*:* }
#smart cards
#allow id xxxx:xxxx with-interface one-of { 0B:*:* }
########### DEFAULT #################
#Everything connected during service startup will otherwise be allowed in this configuration.
#Everything connected later will be rejected.
Please note that misconfigurations to the usbguard
configuration may make the respective USB devices
temporarily unusable on your host. The log file available at /var/log/usbguard/usbguard.log
may help
to investigate issues.
At the end of the configuration, you may have to restart the service via systemctl restart usbguard
.
Also make sure that it is enabled at boot time via systemctl enable usbguard
.
Script to temporarily allow new devices
To temporarily allow new devices for 60 seconds, you can e.g. use the following script:
#!/bin/bash
#
# Temporarily allow new USB devices.
#
# Assumes ImplicitPolicyTarget=reject in the default configuration.
#
# Related:
# https://github.com/USBGuard/usbguard/issues/367
# https://github.com/USBGuard/usbguard/issues/436
function error {
local msg="$1"
notify-send -u critical -t 90000 "usbguard ERROR" "$msg"
>&2 echo "ERROR: $1"
exit 1
}
[ $EUID -eq 0 ] || error "This script must be run as root."
# This works from usbguard 0.75 on (only Qubes 4.1+):
policy="$(usbguard get-parameter ImplicitPolicyTarget)" || error "Failed to retrieve the current usbguard policy."
[[ "$policy" == "allow" ]] && error "Already allowing everything. No need to run."
usbguard set-parameter ImplicitPolicyTarget allow || error "Failed to execute usbguard."
notify-send -t 60000 "usbguard" "Allowing all..."
sleep 60
usbguard set-parameter ImplicitPolicyTarget "$policy" || error "Failed to set usbguard back to its old policy!"
notify-send -t 15000 "usbguard" "${policy}ing again."