USBGUARD-RULES.CO(5)

πŸ’– usbguard-rules.conf(5) πŸ’–

okay bestie, welcome to usbguard-rules.conf β€” the USBGuard rule set file. yes it's a manual page, yes it's long, no you cannot skip it, the rules are literally the whole point. let's go 🫢


✨ NAME ✨

usbguard-rules.conf β€” USBGuard rule set file. that's it, that's the name, short and iconic πŸ‘‘


🌸 DESCRIPTION 🌸

so here's the tea: the usbguard-rules.conf file gets loaded by the USBGuard daemon after it parses the main config file, usbguard-daemon.conf(5). the daemon literally expects this file to contain rules written in a language, and that language is described down in the Rule Language section. so like, keep reading, we get there πŸ’…


πŸ¦‹ RULE LANGUAGE πŸ¦‹

the USBGuard daemon decides which USB device to authorize based on a policy that's defined by a set of rules. no cap.

when a USB device gets inserted into the system, the daemon scans the existing rules sequentially, one after the other. if it finds a matching rule, it either:

  • authorizes (allows) the device,
  • deauthorizes (blocks) the device, or
  • removes (rejects) the device,

...based on the rule target. and if no matching rule is found? then the decision is based on an implicit default target. and that implicit default is to block the device until a decision is made by the user. periodt.

the rule language grammar, expressed in a BNF-like syntax, is literally this:

rule ::= target attributes.

target ::= "allow" | "block" | "reject".

attributes ::= attributes | attribute.
attributes ::= .

rule attributes specify which devices to match, or what condition has to be met for the rule to be applicable. see the Device Specification section for the list of available attributes, and Conditions for the list of supported rule conditions πŸ‘€


🎯 Targets 🎯

the target of a rule specifies whether the device will be authorized for use or not. there are three types of target, and they are recognized like this:

  • allow β€” Authorize the device. the device and its interfaces will be allowed to communicate with the system. slay πŸ’–
  • block β€” Deauthorize the device. the device will remain in a blocked state until it is authorized. it's giving "you're on time-out" πŸ™ˆ
  • reject β€” Deauthorize and Remove the device from the system. the device will have to be re-inserted to become visible to the system again. brutal but fair πŸ’€

πŸ” Device Specification πŸ”

except the target, all the other fields of a rule are optional. a rule where only the target is specified will match any device. that's what lets the policy administrator write an explicit default target. if no rule from the policy is applicable to the device, an implicit target configured in usbguard-daemon.conf(5) will be used.

but if you want to narrow the applicability of a rule down to a set of devices β€” or just one single device β€” you can do that with device attributes and rule conditions. obsessed with the specificity honestly ✨

πŸŽ€ Device Attributes πŸŽ€

device attributes are specific values read from the USB device after it's inserted to the system. which attributes are available is defined below. some of the attributes are derived, and some are based on attributes read directly from the device. all attributes support two forms:

  • single-valued, with a syntax:
name value
  • multi-valued, with a syntax:
name [operator] { value1 value2 ... }

where the optional operator is one of:

  • all-of β€” The device attribute set must contain all of the specified values for the rule to match.
  • one-of β€” The device attribute set must contain at least one of the specified values for the rule to match.
  • none-of β€” The device attribute set must not contain any of the specified values for the rule to match.
  • equals β€” The device attribute set must contain exactly the same set of values for the rule to match.
  • equals-ordered β€” The device attribute set must contain exactly the same set of values in the same order for the rule to match.
  • match-all β€” The device attribute set must be a subset of the specified values for the rule to match.

if the operator is not specified it is set to equals. no thoughts, just defaults πŸ’…

List of attributes:

  • id usb-device-id β€” Match a USB device ID.
  • id [operator] { usb-device-id ... } β€” Match a set of USB device IDs.
  • hash "value" β€” Match a hash computed from the device attribute values and the USB descriptor data. the hash is computed for every device by USBGuard. πŸ”₯
  • hash [operator] { "value" ... } β€” Match a set of device hashes.
  • parent-hash "value" β€” Match a hash of the parent device.
  • parent-hash [operator] { "value" ... } β€” Match a set of parent device hashes.
  • name "device-name" β€” Match the USB device name attribute.
  • name [operator] { "device-name" ... } β€” Match a set of USB device names.
  • serial "serial-number" β€” Match the USB iSerial device attribute.
  • serial [operator] { "serial-number" ... } β€” Match a set of USB iSerial device attributes.
  • via-port "port-id" β€” Match the USB port through which the device is connected. ⚠️ note that some systems have unstable port numbering. the port might change after the system reboots, or when certain kernel modules are reloaded. use the parent-hash attribute if you want to ensure that a device is connected via a specific parent device. this is your "please don't @ me later" moment 😭
  • via-port [operator] { "port-id" ... } β€” Match a set of USB ports.
  • with-interface interface-type β€” Match an interface type that the USB device provides.
  • with-interface [operator] { interface-type ... } β€” Match a set of interface types against the set of interfaces that the USB device provides.
  • with-connect-type "connect-type" β€” Match the USB port/connect_type device attribute.
  • with-connect-type [operator] { "connect-type" ... } β€” Match a set of USB port/connect_type device attributes.
  • label "label" β€” Associates an arbitrary string with a rule. label is useful for storing some contextual information about a rule, or for filtering rules by label. this attribute is not used when testing if a rule applies to a device. so it's purely decorative-adjacent, main character energy but not actually in the match πŸŽ€

the usb-device-id is a colon delimited pair in the form vendor_id:product_id. all USB devices have this ID assigned by the manufacturer, and it should uniquely identify a USB product type. both vendor_id and product_id are 16-bit numbers represented in hexadecimal base. it's possible to use an asterisk character to match either any device ID *:* or any product ID from a specific vendor, e.g. 1234:*. wildcard slay ⭐

the port-id value is a platform specific USB port identification. on Linux it's in the form of "usbN" in case of a USB controller (more accurately a "root hub") or "bus-port[.port[.port ...]]" (e.g. 1-2, 1-2.1, ...) in case of a USB device.

the interface-type represents a USB interface and should be formatted as three 8-bit numbers in hexadecimal base delimited by a colon character, i.e. cc:ss:pp. the numbers represent the interface class (cc), subclass (ss) and protocol (pp) as assigned by the USB-IF. see the list of assigned classes, subclasses and protocols for details.

🚨 heads up bestie: instead of the subclass and protocol number, you may write an asterisk character (*) to match all subclasses or protocols. matching a specific class and a specific protocol is not allowed, i.e. if you use an asterisk as the subclass number, you have to use an asterisk for the protocol too. it's a package deal, no halfsies πŸ’€

🧚 Conditions 🧚

whether a rule that matches a device will be applied or not can be further restricted using rule conditions. if the condition expression is met at the rule evaluation time, then the rule target is applied for the device. a condition expression is met if it evaluates to true. otherwise, the rule evaluation continues with the next rule. a rule condition has the following syntax:

 if [!]condition
 if [operator] { [!]conditionA [!]conditionB ... }

optionally, an exclamation mark (!) can be used to negate the result of a condition. it's the "actually, no" of the rule language ✨

interpretation of the set operator:

  • all-of β€” Evaluate to true if all of the specified conditions evaluated to true.
  • one-of β€” Evaluate to true if one of the specified conditions evaluated to true.
  • none-of β€” Evaluate to true if none of the specified conditions evaluated to true.
  • equals β€” Same as all-of.
  • equals-ordered β€” Same as all-of.

List of conditions:

  • localtime(time_range) β€” Evaluates to true if the local time is in the specified time range. time_range can be written either as HH:MM[:SS] or HH:MM[:SS]-HH:MM[:SS].
  • allowed-matches(query) β€” Evaluates to true if an allowed device matches the specified query. the query uses the rule syntax. conditions in the query are not evaluated. πŸ™ˆ
  • rule-applied β€” Evaluates to true if the rule currently being evaluated ever matched a device.
  • rule-applied(past_duration) β€” Evaluates to true if the rule currently being evaluated matched a device in the past duration of time specified by the parameter. past_duration can be written as HH:MM:SS, HH:MM, or SS.
  • rule-evaluated β€” Evaluates to true if the rule currently being evaluated was ever evaluated before.
  • rule-evaluated(past_duration) β€” Evaluates to true if the rule currently being evaluated was evaluated in the pas duration of time specified by the parameter. past_duration can be written as HH:MM:SS, HH:MM, or SS.
  • random β€” Evaluates to true/false with a probability of p(true)=0.5. a literal coin flip, iconic 🎲
  • random(p_true) β€” Evaluates to true with the specified probability p(true)=p_true.
  • true β€” Evaluates always to true.
  • false β€” Evaluates always to false.

πŸ“ Partial rule πŸ“

a partial rule is a rule without a rule target. partial rules may be used by some commands of the usbguard CLI tool.


πŸ’œ Comments πŸ’œ

in order to easily understand the meaning of each rule, comments can be used. everything after the # character is ignored by the rule parser. so go ahead, leave yourself little love notes, the parser won't judge 🫢


🌈 INITIAL POLICY 🌈

using the usbguard CLI tool and its generate-policy subcommand, you can generate an initial policy for your system instead of writing one from scratch. the tool generates an allow policy for all devices connected to the system at the time of execution. it has several options to tweak the resulting policy, see usbguard(1) for further details.

the policy will be printed out on the standard output. it's a good idea to review the generated rules before using them on a system. the typical workflow for generating an initial policy could look like this:

$ sudo usbguard generate-policy > rules.conf
$ vi rules.conf
(review/modify the rule set)
$ sudo install -m 0600 -o root -g root rules.conf /etc/usbguard/rules.conf
$ sudo systemctl restart usbguard

and that's the vibe so far... ✨

πŸŽ€ EXAMPLE POLICIES πŸŽ€

okay bestie, this is the fun part β€” these are the actual vibes you can drop straight into your rules.conf file to make a whole policy happen. five (5) iconic little scenarios, let's go πŸ’…


1. Allow USB mass storage devices (USB flash disks) and block everything else 🌸

This one is giving ✨strict but fair✨. It blocks any device that isn't just a mass storage device β€” so if somebody's sneaky little USB flash disk is hiding a keyboard interface inside it? Blocked. Absolutely not, we don't do that here. Only devices with a single mass storage interface get to interact with the operating system, periodt.

The whole policy is literally one single rule:

allow with-interface equals { 08:*:* }

And the blocking? It's implicit β€” because we didn't write a block rule at all. Implicit blocking is lowkey perfect for desktop users 🫢, because a desktop applet that's listening to USBGuard events can just ask the user for a decision if an implicit target was applied. cute, right?


2. Allow a specific Yubikey device to be connected via a specific port (and reject everything else on that port) πŸ”‘

allow 1050:0011 name "Yubico Yubikey II" serial "0001234567" via-port "1-2" hash "044b5e168d40ee0245478416caf3d998"
reject via-port "1-2"

ngl we could just use the hash to match this device and call it a day. But here's the tea β˜• β€” the name and serial attributes give you a super useful hint for later inspection of the policy, like a little note-to-self. On the other hand, the hash is the most specific value we can possibly use to identify a device, so if you want a rule that matches just one device and nothing else in the whole universe? hash is your girl. πŸ‘‘


3. Reject devices with suspicious combination of interfaces 🚩

A USB flash disk that's also implementing a keyboard or a network interface is very suspicious β€” like, ma'am, why do you need to type?? 😭 The following set of rules forms a policy that allows USB flash disks and explicitly rejects devices with an additional and suspicious (as defined before) interface:

allow with-interface equals { 08:*:* }
reject with-interface all-of { 08:*:* 03:00:* }
reject with-interface all-of { 08:*:* 03:01:* }
reject with-interface all-of { 08:*:* e0:*:* }
reject with-interface all-of { 08:*:* 02:*:* }

So this policy rejects all USB flash disk devices with an interface from the HID/Keyboard, Communications and Wireless classes. bye πŸ‘‹

⚠️ Important vibe check: default allow is the wrong approach and you shouldn't just reject a set of devices and allow the rest. The policy above assumes that blocking is the default. Rejecting a set of devices considered as "bad" is a good approach for how to limit the exposure of the OS to such devices as much as possible. protect your peace AND your kernel 🫢

4. Allow a keyboard-only USB device only if there isn't already a USB device with a keyboard interface allowed ⌨️

allow with-interface one-of { 03:00:01 03:01:01 } if !allowed-matches(with-interface one-of { 03:00:01 03:01:01 })

one keyboard at a time bestie, we're not running a keyboard party in here πŸ’…


5. Play "Russian roulette" with USB devices πŸŽ²πŸ’€

allow if random(0.1666)
reject

not me recommending you gamble with your hardware 😭 iconic behaviour honestly


πŸ‘€ SEE ALSO πŸ‘€


πŸ› BUGS πŸ›

If you find a bug in this software, or if you'd like to request a feature to be implemented (we love a glow-up ✨), please file a ticket at https://github.com/USBGuard/usbguard/issues/new.


πŸ’– AUTHOR πŸ’–

USBGuard was originally written by Daniel Kopeček. Many people have contributed to it. 🫢


🌈 RESOURCES 🌈

Main web site: https://usbguard.github.io/


πŸ“œ COPYING πŸ“œ

License GPLv2+: GNU GPL version 2 or later http://gnu.org/licenses/gpl.html. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.


okay and that's the whole page, bestie β€” this version is from the USBGuard source, dated 04/15/2026, and it's the USBGUARD-RULES.CO(5) manual page. go forth and write the most immaculate rules.conf of your life, you absolute legend πŸ‘‘βœ¨πŸ’œ

πŸ“¦ where this page comes from