diff --git a/man/udev.xml b/man/udev.xml
index a41a39a43f..4f230c206c 100644
--- a/man/udev.xml
+++ b/man/udev.xml
@@ -23,7 +23,8 @@
Dynamic device management
- Description
+
+ Descriptionudev supplies the system software with device events, manages permissions
of device nodes and may create additional symlinks in the /dev/
directory, or renames network interfaces. The kernel usually just assigns unpredictable
@@ -44,7 +45,8 @@
sources is provided by the library libudev.
- Rules Files
+
+ Rules FilesThe udev rules are read from the files located in the system rules directories
/usr/lib/udev/rules.d and /usr/local/lib/udev/rules.d, the
volatile runtime directory /run/udev/rules.d and the local administration
@@ -68,727 +70,749 @@
pointing to the device node, or run a specified program as part of
the event handling.
- A rule consists of a comma-separated list of one or more key-value pairs.
- Each key has a distinct operation, depending on the used operator. Valid
- operators are:
-
-
- ==
-
- Compare for equality.
-
-
+ A rule consists of a comma-separated list of one or more key-operator-value expressions.
+ Each expression has a distinct effect, depending on the key and operator used.
-
- !=
-
- Compare for inequality.
-
-
+
+ Operators
+
+
+ ==
+
+ Compare for equality.
+
+
-
- =
-
- Assign a value to a key. Keys that represent a list are reset
- and only this single value is assigned.
-
-
+
+ !=
+
+ Compare for inequality.
+
+
-
- +=
-
- Add the value to a key that holds a list of entries.
-
-
+
+ =
+
+ Assign a value to a key. Keys that represent a list are reset
+ and only this single value is assigned.
+
+
-
- -=
-
- Remove the value from a key that holds a list of entries.
-
-
+
+ +=
+
+ Add the value to a key that holds a list of entries.
+
+
-
- :=
-
- Assign a value to a key finally; disallow any later changes.
-
-
-
+
+ -=
+
+ Remove the value from a key that holds a list of entries.
+
+
- The following key names can be used to match against device properties.
- Some of the keys also match against properties of the parent devices in sysfs,
- not only the device that has generated the event. If multiple keys that match
- a parent device are specified in a single rule, all these keys must match at
- one and the same parent device.
-
-
- ACTION
-
- Match the name of the event action.
-
-
+
+ :=
+
+ Assign a value to a key finally; disallow any later changes.
+
+
+
+
-
- DEVPATH
-
- Match the devpath of the event device.
-
-
+
+ Values
+ Values are written as double quoted strings, such as ("string").
+ To include a quotation mark (") in the value, precede it by a backslash (\").
+ Any other occurrences of a character followed by a backslash are not further unescaped.
+ That is, "\t\n" is treated as four characters:
+ backslash, lowercase t, backslash, lowercase n.
-
- KERNEL
-
- Match the name of the event device.
-
-
+ The string can be prefixed with a lowercase e (e"string\n") to mark the string as
+ C-style escaped.
+ For example, e"string\n" is parsed as 7 characters: 6 lowercase letters and a newline.
+ This can be useful for writting special characters when a kernel driver requires them.
-
- NAME
-
- Match the name of a network interface. It can be used once the
- NAME key has been set in one of the preceding rules.
-
-
+ Please note that NUL is not allowed in either string variant.
+
-
- SYMLINK
-
- Match the name of a symlink targeting the node. It can
- be used once a SYMLINK key has been set in one of the preceding
- rules. There may be multiple symlinks; only one needs to match.
-
-
-
+
+ Keys
+ The following key names can be used to match against device properties.
+ Some of the keys also match against properties of the parent devices in sysfs,
+ not only the device that has generated the event. If multiple keys that match
+ a parent device are specified in a single rule, all these keys must match at
+ one and the same parent device.
+
+
+ ACTION
+
+ Match the name of the event action.
+
+
-
- SUBSYSTEM
-
- Match the subsystem of the event device.
-
-
-
- DRIVER
-
- Match the driver name of the event device. Only set this key for devices
- which are bound to a driver at the time the event is generated.
-
-
-
- ATTR{filename}
-
- Match sysfs attribute values of the event device. Trailing
- whitespace in the attribute values is ignored unless the specified match
- value itself contains trailing whitespace.
-
-
-
-
- SYSCTL{kernel parameter}
-
- Match a kernel parameter value.
-
-
-
+
+ DEVPATH
+
+ Match the devpath of the event device.
+
+
-
- KERNELS
-
- Search the devpath upwards for a matching device name.
-
-
+
+ KERNEL
+
+ Match the name of the event device.
+
+
-
- SUBSYSTEMS
-
- Search the devpath upwards for a matching device subsystem name.
-
-
+
+ NAME
+
+ Match the name of a network interface. It can be used once the
+ NAME key has been set in one of the preceding rules.
+
+
-
- DRIVERS
-
- Search the devpath upwards for a matching device driver name.
-
-
+
+ SYMLINK
+
+ Match the name of a symlink targeting the node. It can
+ be used once a SYMLINK key has been set in one of the preceding
+ rules. There may be multiple symlinks; only one needs to match.
+
+
+
-
- ATTRS{filename}
-
- Search the devpath upwards for a device with matching sysfs attribute values.
- If multiple ATTRS matches are specified, all of them
- must match on the same device. Trailing whitespace in the attribute values is ignored
- unless the specified match value itself contains trailing whitespace.
-
-
+
+ SUBSYSTEM
+
+ Match the subsystem of the event device.
+
+
+
+ DRIVER
+
+ Match the driver name of the event device. Only set this key for devices
+ which are bound to a driver at the time the event is generated.
+
+
+
+ ATTR{filename}
+
+ Match sysfs attribute values of the event device. Trailing
+ whitespace in the attribute values is ignored unless the specified match
+ value itself contains trailing whitespace.
+
+
+
+
+ SYSCTL{kernel parameter}
+
+ Match a kernel parameter value.
+
+
+
-
- TAGS
-
- Search the devpath upwards for a device with matching tag.
-
-
+
+ KERNELS
+
+ Search the devpath upwards for a matching device name.
+
+
-
- ENV{key}
-
- Match against a device property value.
-
-
+
+ SUBSYSTEMS
+
+ Search the devpath upwards for a matching device subsystem name.
+
+
-
- CONST{key}
-
- Match against a system-wide constant. Supported keys are:
-
+
+ DRIVERS
+
+ Search the devpath upwards for a matching device driver name.
+
+
+
+
+ ATTRS{filename}
+
+ Search the devpath upwards for a device with matching sysfs attribute values.
+ If multiple ATTRS matches are specified, all of them
+ must match on the same device. Trailing whitespace in the attribute values is ignored
+ unless the specified match value itself contains trailing whitespace.
+
+
+
+
+ TAGS
+
+ Search the devpath upwards for a device with matching tag.
+
+
+
+
+ ENV{key}
+
+ Match against a device property value.
+
+
+
+
+ CONST{key}
+
+ Match against a system-wide constant. Supported keys are:
+
+
+ arch
+
+ System's architecture. See in
+ systemd.unit5
+ for possible values.
+
+
+
+ virt
+
+ System's virtualization environment. See
+ systemd-detect-virt1
+ for possible values.
+
+
+
+ Unknown keys will never match.
+
+
+
+
+ TAG
+
+ Match against a device tag.
+
+
+
+
+ TEST{octal mode mask}
+
+ Test the existence of a file. An octal mode mask can be specified
+ if needed.
+
+
+
+
+ PROGRAM
+
+ Execute a program to determine whether there is a match; the key is true if the program
+ returns successfully. The device properties are made available to the executed program in the
+ environment. The program's standard output is available in the RESULT
+ key.
+
+ This can only be used for very short-running foreground tasks. For details, see
+ RUN.
+
+ Note that multiple PROGRAM keys may be specified in one rule, and
+ =, :=, and += have the same effect as
+ ==.
+
+
+
+
+ RESULT
+
+ Match the returned string of the last PROGRAM call.
+ This key can be used in the same or in any later rule after a
+ PROGRAM call.
+
+
+
+
+ Most of the fields support shell glob pattern matching and
+ alternate patterns. The following special characters are supported:
+
+
+ *
+
+ Matches zero or more characters.
+
+
+
+ ?
+
+ Matches any single character.
+
+
+
+ []
+
+ Matches any single character specified within the brackets. For
+ example, the pattern string tty[SR]
+ would match either ttyS or ttyR.
+ Ranges are also supported via the - character.
+ For example, to match on the range of all digits, the pattern
+ [0-9] could be used. If the first character
+ following the [ is a !,
+ any characters not enclosed are matched.
+
+
+
+ |
+
+ Separates alternative patterns. For example, the pattern string
+ abc|x* would match either abc
+ or x*.
+
+
+
+
+ The following keys can get values assigned:
+
+
+ NAME
+
+ The name to use for a network interface. See
+ systemd.link5
+ for a higher-level mechanism for setting the interface name.
+ The name of a device node cannot be changed by udev, only additional
+ symlinks can be created.
+
+
+
+
+ SYMLINK
+
+ The name of a symlink targeting the node. Every matching rule adds
+ this value to the list of symlinks to be created.
+ The set of characters to name a symlink is limited. Allowed
+ characters are 0-9A-Za-z#+-.:=@_/, valid UTF-8 character
+ sequences, and \x00 hex encoding. All other
+ characters are replaced by a _ character.
+ Multiple symlinks may be specified by separating the names by the
+ space character. In case multiple devices claim the same name, the link
+ always points to the device with the highest link_priority. If the current
+ device goes away, the links are re-evaluated and the device with the
+ next highest link_priority becomes the owner of the link. If no
+ link_priority is specified, the order of the devices (and which one of
+ them owns the link) is undefined.
+ Symlink names must never conflict with the kernel's default device
+ node names, as that would result in unpredictable behavior.
+
+
+
+
+
+ OWNER, GROUP, MODE
+
+ The permissions for the device node. Every specified value overrides
+ the compiled-in default value.
+
+
+
+
+ SECLABEL{module}
+
+ Applies the specified Linux Security Module label to the device node.
+
+
+
+
+ ATTR{key}
+
+ The value that should be written to a sysfs attribute of the
+ event device.
+
+
+
+
+ SYSCTL{kernel parameter}
+
+ The value that should be written to kernel parameter.
+
+
+
+
+ ENV{key}
+
+ Set a device property value. Property names with a leading .
+ are neither stored in the database nor exported to events or
+ external tools (run by, for example, the PROGRAM
+ match key).
+
+
+
+
+ TAG
+
+ Attach a tag to a device. This is used to filter events for users
+ of libudev's monitor functionality, or to enumerate a group of tagged
+ devices. The implementation can only work efficiently if only a few
+ tags are attached to a device. It is only meant to be used in
+ contexts with specific device filter requirements, and not as a
+ general-purpose flag. Excessive use might result in inefficient event
+ handling.
+
+
+
+
+ RUN{type}
+
+ Specify a program to be executed after processing of all the rules for the event. With
+ +=, this invocation is added to the list, and with = or
+ :=, it replaces any previous contents of the list. Please note that both
+ program and builtin types described below use a single
+ list, so clearing the list with := and = affects both
+ types.
+
+ type may be:
+
+
+ program
+
+ Execute an external program specified as the assigned
+ value. If no absolute path is given, the program is expected
+ to live in /usr/lib/udev; otherwise, the
+ absolute path must be specified.
+ This is the default if no type
+ is specified.
+
+
+
+ builtin
+
+ As program, but use one of the
+ built-in programs rather than an external one.
+
+
+
+
+ The program name and following arguments are separated by spaces. Single quotes can be
+ used to specify arguments with spaces.
+
+ This can only be used for very short-running foreground tasks. Running an event process for
+ a long period of time may block all further events for this or a dependent device.
+
+ Note that running programs that access the network or mount/unmount filesystems is not
+ allowed inside of udev rules, due to the default sandbox that is enforced on
+ systemd-udevd.service.
+
+ Starting daemons or other long-running processes is not allowed; the forked processes,
+ detached or not, will be unconditionally killed after the event handling has finished. In order
+ to activate long-running processes from udev rules, provide a service unit and pull it in from a
+ udev device using the SYSTEMD_WANTS device property. See
+ systemd.device5
+ for details.
+
+
+
+
+ LABEL
+
+ A named label to which a GOTO may jump.
+
+
+
+
+ GOTO
+
+ Jumps to the next LABEL with a matching name.
+
+
+
+
+ IMPORT{type}
+
+ Import a set of variables as device properties, depending on
+ type:
+
+
+
+ program
+
+ Execute an external program specified as the assigned
+ value and, if it returns successfully,
+ import its output, which must be in environment key
+ format. Path specification, command/argument separation,
+ and quoting work like in RUN.
+
+
+
+ builtin
+
+ Similar to program, but use one of the
+ built-in programs rather than an external one.
+
+
- arch
-
- System's architecture. See in
- systemd.unit5
- for possible values.
-
-
-
- virt
-
- System's virtualization environment. See
- systemd-detect-virt1
- for possible values.
-
-
-
- Unknown keys will never match.
-
-
+ file
+
+ Import a text file specified as the assigned value, the content
+ of which must be in environment key format.
+
+
+
+ db
+
+ Import a single property specified as the assigned value from the
+ current device database. This works only if the database is already populated
+ by an earlier event.
+
+
+
+ cmdline
+
+ Import a single property from the kernel command line. For simple flags
+ the value of the property is set to 1.
+
+
+
+ parent
+
+ Import the stored keys from the parent device by reading
+ the database entry of the parent device. The value assigned to
+ is used as a filter of key names
+ to import (with the same shell glob pattern matching used for
+ comparisons).
+
+
+
-
- TAG
-
- Match against a device tag.
-
-
+ This can only be used for very short-running foreground tasks. For details see
+ .
-
- TEST{octal mode mask}
-
- Test the existence of a file. An octal mode mask can be specified
- if needed.
-
-
+ Note that multiple IMPORT{} keys may be specified in one rule, and
+ =, :=, and += have the same effect as
+ ==. The key is true if the import is successful, unless !=
+ is used as the operator which causes the key to be true if the import failed.
+
+
-
- PROGRAM
-
- Execute a program to determine whether there is a match; the key is true if the program
- returns successfully. The device properties are made available to the executed program in the
- environment. The program's standard output is available in the RESULT
- key.
+
+ OPTIONS
+
+ Rule and device options:
+
+
+
+
+ Specify the priority of the created symlinks. Devices with higher
+ priorities overwrite existing symlinks of other devices. The default is 0.
+
+
+
+
+
+ Usually, control and other possibly unsafe characters are replaced
+ in strings used for device naming. The mode of replacement can be specified
+ with this option.
+
+
+
+
+
+ Apply the permissions specified in this rule to the
+ static device node with the specified name. Also, for every
+ tag specified in this rule, create a symlink
+ in the directory
+ /run/udev/static_node-tags/tag
+ pointing at the static device node with the specified name.
+ Static device node creation is performed by systemd-tmpfiles
+ before systemd-udevd is started. The static nodes might not
+ have a corresponding kernel device; they are used to trigger
+ automatic kernel module loading when they are accessed.
+
+
+
+
+
+ Watch the device node with inotify; when the node is
+ closed after being opened for writing, a change uevent is
+ synthesized.
+
+
+
+
+
+ Disable the watching of a device node with inotify.
+
+
+
+
+
+ Set the flag (sticky bit) on the udev database entry
+ of the event device. Device properties are then kept in the
+ database even when
+ udevadm info --cleanup-db is called.
+ This option can be useful in certain cases
+ (e.g. Device Mapper devices) for persisting device state
+ on the transition from initramfs.
+
+
+
+
+
+
- This can only be used for very short-running foreground tasks. For details, see
- RUN.
+ The NAME, SYMLINK,
+ PROGRAM, OWNER,
+ GROUP, MODE, SECLABEL,
+ and RUN fields support simple string substitutions.
+ The RUN substitutions are performed after all rules
+ have been processed, right before the program is executed, allowing for
+ the use of device properties set by earlier matching rules. For all other
+ fields, substitutions are performed while the individual rule is being
+ processed. The available substitutions are:
+
+
+ ,
+
+ The kernel name for this device.
+
+
- Note that multiple PROGRAM keys may be specified in one rule, and
- =, :=, and += have the same effect as
- ==.
-
-
+
+ ,
+
+ The kernel number for this device. For example, sda3 has kernel number
+ 3.
+
+
-
- RESULT
-
- Match the returned string of the last PROGRAM call.
- This key can be used in the same or in any later rule after a
- PROGRAM call.
-
-
-
+
+ ,
+
+ The devpath of the device.
+
+
- Most of the fields support shell glob pattern matching and
- alternate patterns. The following special characters are supported:
-
-
- *
-
- Matches zero or more characters.
-
-
-
- ?
-
- Matches any single character.
-
-
-
- []
-
- Matches any single character specified within the brackets. For
- example, the pattern string tty[SR]
- would match either ttyS or ttyR.
- Ranges are also supported via the - character.
- For example, to match on the range of all digits, the pattern
- [0-9] could be used. If the first character
- following the [ is a !,
- any characters not enclosed are matched.
-
-
-
- |
-
- Separates alternative patterns. For example, the pattern string
- abc|x* would match either abc
- or x*.
-
-
-
+
+ ,
+
+ The name of the device matched while searching the devpath
+ upwards for , ,
+ , and .
+
+
+
- The following keys can get values assigned:
-
-
- NAME
-
- The name to use for a network interface. See
- systemd.link5
- for a higher-level mechanism for setting the interface name.
- The name of a device node cannot be changed by udev, only additional
- symlinks can be created.
-
-
+
+
+
+ The driver name of the device matched while searching the
+ devpath upwards for ,
+ , , and
+ .
+
+
+
-
- SYMLINK
-
- The name of a symlink targeting the node. Every matching rule adds
- this value to the list of symlinks to be created.
- The set of characters to name a symlink is limited. Allowed
- characters are 0-9A-Za-z#+-.:=@_/, valid UTF-8 character
- sequences, and \x00 hex encoding. All other
- characters are replaced by a _ character.
- Multiple symlinks may be specified by separating the names by the
- space character. In case multiple devices claim the same name, the link
- always points to the device with the highest link_priority. If the current
- device goes away, the links are re-evaluated and the device with the
- next highest link_priority becomes the owner of the link. If no
- link_priority is specified, the order of the devices (and which one of
- them owns the link) is undefined.
- Symlink names must never conflict with the kernel's default device
- node names, as that would result in unpredictable behavior.
-
-
-
+
+ ,
+
+ The value of a sysfs attribute found at the device where
+ all keys of the rule have matched. If the matching device does not
+ have such an attribute, and a previous ,
+ , , or
+ test selected a parent device, then the
+ attribute from that parent device is used.
+
+ If the attribute is a symlink, the last element of the
+ symlink target is returned as the value.
+
+
+
-
- OWNER, GROUP, MODE
-
- The permissions for the device node. Every specified value overrides
- the compiled-in default value.
-
-
+
+ ,
+
+ A device property value.
+
+
-
- SECLABEL{module}
-
- Applies the specified Linux Security Module label to the device node.
-
-
+
+ ,
+
+ The kernel major number for the device.
+
+
-
- ATTR{key}
-
- The value that should be written to a sysfs attribute of the
- event device.
-
-
+
+ ,
+
+ The kernel minor number for the device.
+
+
-
- SYSCTL{kernel parameter}
-
- The value that should be written to kernel parameter.
-
-
+
+ ,
+
+ The string returned by the external program requested with
+ PROGRAM.
+ A single part of the string, separated by a space character, may be selected
+ by specifying the part number as an attribute: %c{N}.
+ If the number is followed by the + character, this part plus all remaining parts
+ of the result string are substituted: %c{N+}.
+
+
-
- ENV{key}
-
- Set a device property value. Property names with a leading .
- are neither stored in the database nor exported to events or
- external tools (run by, for example, the PROGRAM
- match key).
-
-
+
+ ,
+
+ The node name of the parent device.
+
+
-
- TAG
-
- Attach a tag to a device. This is used to filter events for users
- of libudev's monitor functionality, or to enumerate a group of tagged
- devices. The implementation can only work efficiently if only a few
- tags are attached to a device. It is only meant to be used in
- contexts with specific device filter requirements, and not as a
- general-purpose flag. Excessive use might result in inefficient event
- handling.
-
-
+
+
+
+ The current name of the device. If not changed by a rule, it is the
+ name of the kernel device.
+
+
-
- RUN{type}
-
- Specify a program to be executed after processing of all the rules for the event. With
- +=, this invocation is added to the list, and with = or
- :=, it replaces any previous contents of the list. Please note that both
- program and builtin types described below use a single
- list, so clearing the list with := and = affects both
- types.
+
+
+
+ A space-separated list of the current symlinks. The value is
+ only set during a remove event or if an earlier rule assigned a value.
+
+
- type may be:
-
-
- program
-
- Execute an external program specified as the assigned
- value. If no absolute path is given, the program is expected
- to live in /usr/lib/udev; otherwise, the
- absolute path must be specified.
- This is the default if no type
- is specified.
-
-
-
- builtin
-
- As program, but use one of the
- built-in programs rather than an external one.
-
-
-
+
+ ,
+
+ The udev_root value.
+
+
- The program name and following arguments are separated by spaces. Single quotes can be
- used to specify arguments with spaces.
+
+ ,
+
+ The sysfs mount point.
+
+
- This can only be used for very short-running foreground tasks. Running an event process for
- a long period of time may block all further events for this or a dependent device.
+
+ ,
+
+ The name of the device node.
+
+
- Note that running programs that access the network or mount/unmount filesystems is not
- allowed inside of udev rules, due to the default sandbox that is enforced on
- systemd-udevd.service.
+
+
+
+ The % character itself.
+
+
- Starting daemons or other long-running processes is not allowed; the forked processes,
- detached or not, will be unconditionally killed after the event handling has finished. In order
- to activate long-running processes from udev rules, provide a service unit and pull it in from a
- udev device using the SYSTEMD_WANTS device property. See
- systemd.device5
- for details.
-
-
-
-
- LABEL
-
- A named label to which a GOTO may jump.
-
-
-
-
- GOTO
-
- Jumps to the next LABEL with a matching name.
-
-
-
-
- IMPORT{type}
-
- Import a set of variables as device properties, depending on
- type:
-
-
-
- program
-
- Execute an external program specified as the assigned
- value and, if it returns successfully,
- import its output, which must be in environment key
- format. Path specification, command/argument separation,
- and quoting work like in RUN.
-
-
-
- builtin
-
- Similar to program, but use one of the
- built-in programs rather than an external one.
-
-
-
- file
-
- Import a text file specified as the assigned value, the content
- of which must be in environment key format.
-
-
-
- db
-
- Import a single property specified as the assigned value from the
- current device database. This works only if the database is already populated
- by an earlier event.
-
-
-
- cmdline
-
- Import a single property from the kernel command line. For simple flags
- the value of the property is set to 1.
-
-
-
- parent
-
- Import the stored keys from the parent device by reading
- the database entry of the parent device. The value assigned to
- is used as a filter of key names
- to import (with the same shell glob pattern matching used for
- comparisons).
-
-
-
-
- This can only be used for very short-running foreground tasks. For details see
- .
-
- Note that multiple IMPORT{} keys may be specified in one rule, and
- =, :=, and += have the same effect as
- ==. The key is true if the import is successful, unless !=
- is used as the operator which causes the key to be true if the import failed.
-
-
-
-
- OPTIONS
-
- Rule and device options:
-
-
-
-
- Specify the priority of the created symlinks. Devices with higher
- priorities overwrite existing symlinks of other devices. The default is 0.
-
-
-
-
-
- Usually, control and other possibly unsafe characters are replaced
- in strings used for device naming. The mode of replacement can be specified
- with this option.
-
-
-
-
-
- Apply the permissions specified in this rule to the
- static device node with the specified name. Also, for every
- tag specified in this rule, create a symlink
- in the directory
- /run/udev/static_node-tags/tag
- pointing at the static device node with the specified name.
- Static device node creation is performed by systemd-tmpfiles
- before systemd-udevd is started. The static nodes might not
- have a corresponding kernel device; they are used to trigger
- automatic kernel module loading when they are accessed.
-
-
-
-
-
- Watch the device node with inotify; when the node is
- closed after being opened for writing, a change uevent is
- synthesized.
-
-
-
-
-
- Disable the watching of a device node with inotify.
-
-
-
-
-
- Set the flag (sticky bit) on the udev database entry
- of the event device. Device properties are then kept in the
- database even when
- udevadm info --cleanup-db is called.
- This option can be useful in certain cases
- (e.g. Device Mapper devices) for persisting device state
- on the transition from initramfs.
-
-
-
-
-
-
-
- The NAME, SYMLINK,
- PROGRAM, OWNER,
- GROUP, MODE, SECLABEL,
- and RUN fields support simple string substitutions.
- The RUN substitutions are performed after all rules
- have been processed, right before the program is executed, allowing for
- the use of device properties set by earlier matching rules. For all other
- fields, substitutions are performed while the individual rule is being
- processed. The available substitutions are:
-
-
- ,
-
- The kernel name for this device.
-
-
-
-
- ,
-
- The kernel number for this device. For example, sda3 has kernel number
- 3.
-
-
-
-
- ,
-
- The devpath of the device.
-
-
-
-
- ,
-
- The name of the device matched while searching the devpath
- upwards for , ,
- , and .
-
-
-
-
-
-
-
- The driver name of the device matched while searching the
- devpath upwards for ,
- , , and
- .
-
-
-
-
-
- ,
-
- The value of a sysfs attribute found at the device where
- all keys of the rule have matched. If the matching device does not
- have such an attribute, and a previous ,
- , , or
- test selected a parent device, then the
- attribute from that parent device is used.
-
- If the attribute is a symlink, the last element of the
- symlink target is returned as the value.
-
-
-
-
-
- ,
-
- A device property value.
-
-
-
-
- ,
-
- The kernel major number for the device.
-
-
-
-
- ,
-
- The kernel minor number for the device.
-
-
-
-
- ,
-
- The string returned by the external program requested with
- PROGRAM.
- A single part of the string, separated by a space character, may be selected
- by specifying the part number as an attribute: %c{N}.
- If the number is followed by the + character, this part plus all remaining parts
- of the result string are substituted: %c{N+}.
-
-
-
-
- ,
-
- The node name of the parent device.
-
-
-
-
-
-
- The current name of the device. If not changed by a rule, it is the
- name of the kernel device.
-
-
-
-
-
-
- A space-separated list of the current symlinks. The value is
- only set during a remove event or if an earlier rule assigned a value.
-
-
-
-
- ,
-
- The udev_root value.
-
-
-
-
- ,
-
- The sysfs mount point.
-
-
-
-
- ,
-
- The name of the device node.
-
-
-
-
-
-
- The % character itself.
-
-
-
-
-
-
- The $ character itself.
-
-
-
+
+
+
+ The $ character itself.
+
+
+
+
diff --git a/src/fuzz/fuzz-udev-rule-parse-value.c b/src/fuzz/fuzz-udev-rule-parse-value.c
new file mode 100644
index 0000000000..f1d36669c4
--- /dev/null
+++ b/src/fuzz/fuzz-udev-rule-parse-value.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include
+
+#include "alloc-util.h"
+#include "fuzz.h"
+#include "udev-util.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ _cleanup_free_ char *str = NULL;
+ int r;
+ char *value = UINT_TO_PTR(0x12345678U);
+ char *endpos = UINT_TO_PTR(0x87654321U);
+
+ assert_se(str = malloc(size + 1));
+ memcpy(str, data, size);
+ str[size] = '\0';
+
+ r = udev_rule_parse_value(str, &value, &endpos);
+
+ if (r < 0) {
+ /* not modified on failure */
+ assert_se(value == UINT_TO_PTR(0x12345678U));
+ assert_se(endpos == UINT_TO_PTR(0x87654321U));
+ } else {
+ assert_se(endpos <= str + size);
+ assert_se(endpos > str + 1);
+ }
+
+ return 0;
+}
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
index 01f119fcd0..9b5491940d 100644
--- a/src/fuzz/meson.build
+++ b/src/fuzz/meson.build
@@ -152,4 +152,8 @@ fuzzers += [
'src/xdg-autostart-generator/xdg-autostart-service.c'],
[],
[]],
+
+ [['src/fuzz/fuzz-udev-rule-parse-value.c'],
+ [libshared],
+ []],
]
diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c
index 33272de4bc..7bb9f40a75 100644
--- a/src/shared/udev-util.c
+++ b/src/shared/udev-util.c
@@ -6,13 +6,16 @@
#include "alloc-util.h"
#include "device-util.h"
#include "env-file.h"
+#include "escape.h"
#include "log.h"
+#include "macro.h"
#include "parse-util.h"
#include "path-util.h"
#include "signal-util.h"
#include "string-table.h"
#include "string-util.h"
#include "udev-util.h"
+#include "utf8.h"
static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = {
[RESOLVE_NAME_NEVER] = "never",
@@ -320,3 +323,49 @@ bool device_for_action(sd_device *dev, DeviceAction action) {
return a == action;
}
+
+int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
+ char *i, *j;
+ int r;
+ bool is_escaped;
+
+ /* value must be double quotated */
+ is_escaped = str[0] == 'e';
+ str += is_escaped;
+ if (str[0] != '"')
+ return -EINVAL;
+ str++;
+
+ if (!is_escaped) {
+ /* unescape double quotation '\"'->'"' */
+ for (i = j = str; *i != '"'; i++, j++) {
+ if (*i == '\0')
+ return -EINVAL;
+ if (i[0] == '\\' && i[1] == '"')
+ i++;
+ *j = *i;
+ }
+ j[0] = '\0';
+ } else {
+ _cleanup_free_ char *unescaped = NULL;
+
+ /* find the end position of value */
+ for (i = str; *i != '"'; i++) {
+ if (i[0] == '\\')
+ i++;
+ if (*i == '\0')
+ return -EINVAL;
+ }
+ i[0] = '\0';
+
+ r = cunescape_length(str, i - str, 0, &unescaped);
+ if (r < 0)
+ return r;
+ assert(r <= i - str);
+ memcpy(str, unescaped, r + 1);
+ }
+
+ *ret_value = str;
+ *ret_endpos = i + 1;
+ return 0;
+}
diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h
index 58803ea522..0eb7f81904 100644
--- a/src/shared/udev-util.h
+++ b/src/shared/udev-util.h
@@ -32,3 +32,5 @@ int device_wait_for_initialization(sd_device *device, const char *subsystem, use
int device_wait_for_devlink(const char *path, const char *subsystem, usec_t deadline, sd_device **ret);
int device_is_renaming(sd_device *dev);
bool device_for_action(sd_device *dev, DeviceAction action);
+
+int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos);
diff --git a/src/test/meson.build b/src/test/meson.build
index e4ce8ac51a..fd3e53f05b 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -775,6 +775,10 @@ tests += [
libselinux],
'', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'],
+ [['src/test/test-udev-util.c'],
+ [],
+ []],
+
[['src/test/test-id128.c'],
[],
[]],
diff --git a/src/test/test-udev-util.c b/src/test/test-udev-util.c
new file mode 100644
index 0000000000..c3efdab41a
--- /dev/null
+++ b/src/test/test-udev-util.c
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include
+#include
+
+#include "macro.h"
+#include "string-util.h"
+#include "udev-util.h"
+
+static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, int expected_retval) {
+ _cleanup_free_ char *str = NULL;
+ char *value = UINT_TO_PTR(0x12345678U);
+ char *endpos = UINT_TO_PTR(0x87654321U);
+
+ assert_se(str = strdup(in));
+ assert_se(udev_rule_parse_value(str, &value, &endpos) == expected_retval);
+ if (expected_retval < 0) {
+ /* not modified on failure */
+ assert_se(value == UINT_TO_PTR(0x12345678U));
+ assert_se(endpos == UINT_TO_PTR(0x87654321U));
+ } else {
+ assert_se(streq_ptr(value, expected_value));
+ assert_se(endpos == str + strlen(in));
+ }
+}
+
+static void test_parse_value(void) {
+ /* input: "valid operand"
+ * parsed: valid operand
+ * use the following command to help generate textual C strings:
+ * python3 -c 'import json; print(json.dumps(input()))' */
+ test_udev_rule_parse_value_one(
+ "\"valid operand\"",
+ "valid operand",
+ 0
+ );
+}
+
+static void test_parse_value_with_backslashes(void) {
+ /* input: "va'l\'id\"op\"erand"
+ * parsed: va'l\'id"op"erand */
+ test_udev_rule_parse_value_one(
+ "\"va'l\\'id\\\"op\\\"erand\"",
+ "va'l\\'id\"op\"erand",
+ 0
+ );
+}
+
+static void test_parse_value_no_quotes(void) {
+ test_udev_rule_parse_value_one(
+ "no quotes",
+ 0,
+ -EINVAL
+ );
+}
+
+static void test_parse_value_noescape(void) {
+ test_udev_rule_parse_value_one(
+ "\"\\\\a\\b\\x\\y\"",
+ "\\\\a\\b\\x\\y",
+ 0
+ );
+}
+
+static void test_parse_value_nul(void) {
+ test_udev_rule_parse_value_one(
+ "\"reject\0nul\"",
+ 0,
+ -EINVAL
+ );
+}
+
+static void test_parse_value_escape_nothing(void) {
+ /* input: e"" */
+ test_udev_rule_parse_value_one(
+ "e\"\"",
+ "",
+ 0
+ );
+}
+
+static void test_parse_value_escape_nothing2(void) {
+ /* input: e"1234" */
+ test_udev_rule_parse_value_one(
+ "e\"1234\"",
+ "1234",
+ 0
+ );
+}
+
+static void test_parse_value_escape_double_quote(void) {
+ /* input: e"\"" */
+ test_udev_rule_parse_value_one(
+ "e\"\\\"\"",
+ "\"",
+ 0
+ );
+}
+
+static void test_parse_value_escape_backslash(void) {
+ /* input: e"\ */
+ test_udev_rule_parse_value_one(
+ "e\"\\",
+ 0,
+ -EINVAL
+ );
+ /* input: e"\" */
+ test_udev_rule_parse_value_one(
+ "e\"\\\"",
+ 0,
+ -EINVAL
+ );
+ /* input: e"\\" */
+ test_udev_rule_parse_value_one(
+ "e\"\\\\\"",
+ "\\",
+ 0
+ );
+ /* input: e"\\\" */
+ test_udev_rule_parse_value_one(
+ "e\"\\\\\\\"",
+ 0,
+ -EINVAL
+ );
+ /* input: e"\\\"" */
+ test_udev_rule_parse_value_one(
+ "e\"\\\\\\\"\"",
+ "\\\"",
+ 0
+ );
+ /* input: e"\\\\" */
+ test_udev_rule_parse_value_one(
+ "e\"\\\\\\\\\"",
+ "\\\\",
+ 0
+ );
+}
+
+static void test_parse_value_newline(void) {
+ /* input: e"operand with newline\n" */
+ test_udev_rule_parse_value_one(
+ "e\"operand with newline\\n\"",
+ "operand with newline\n",
+ 0
+ );
+}
+
+static void test_parse_value_escaped(void) {
+ /* input: e"single\rcharacter\t\aescape\bsequence" */
+ test_udev_rule_parse_value_one(
+ "e\"single\\rcharacter\\t\\aescape\\bsequence\"",
+ "single\rcharacter\t\aescape\bsequence",
+ 0
+ );
+}
+
+static void test_parse_value_invalid_escape(void) {
+ /* input: e"reject\invalid escape sequence" */
+ test_udev_rule_parse_value_one(
+ "e\"reject\\invalid escape sequence",
+ 0,
+ -EINVAL
+ );
+}
+
+static void test_parse_value_invalid_termination(void) {
+ /* input: e"\ */
+ test_udev_rule_parse_value_one(
+ "e\"\\",
+ 0,
+ -EINVAL
+ );
+}
+
+static void test_parse_value_unicode(void) {
+ /* input: "s\u1d1c\u1d04\u029c \u1d1c\u0274\u026a\u1d04\u1d0f\u1d05\u1d07 \U0001d568\U0001d560\U0001d568" */
+ test_udev_rule_parse_value_one(
+ "e\"s\\u1d1c\\u1d04\\u029c \\u1d1c\\u0274\\u026a\\u1d04\\u1d0f\\u1d05\\u1d07 \\U0001d568\\U0001d560\\U0001d568\"",
+ "s\xe1\xb4\x9c\xe1\xb4\x84\xca\x9c \xe1\xb4\x9c\xc9\xb4\xc9\xaa\xe1\xb4\x84\xe1\xb4\x8f\xe1\xb4\x85\xe1\xb4\x87 \xf0\x9d\x95\xa8\xf0\x9d\x95\xa0\xf0\x9d\x95\xa8",
+ 0
+ );
+}
+
+int main(int argc, char **argv) {
+ test_parse_value();
+ test_parse_value_with_backslashes();
+ test_parse_value_no_quotes();
+ test_parse_value_nul();
+ test_parse_value_noescape();
+
+ test_parse_value_escape_nothing();
+ test_parse_value_escape_nothing2();
+ test_parse_value_escape_double_quote();
+ test_parse_value_escape_backslash();
+ test_parse_value_newline();
+ test_parse_value_escaped();
+ test_parse_value_invalid_escape();
+ test_parse_value_invalid_termination();
+ test_parse_value_unicode();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 7e029927fd..e01d75580a 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -990,8 +990,9 @@ static UdevRuleOperatorType parse_operator(const char *op) {
}
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value) {
- char *key_begin, *key_end, *attr, *tmp, *value, *i, *j;
+ char *key_begin, *key_end, *attr, *tmp;
UdevRuleOperatorType op;
+ int r;
assert(line);
assert(*line);
@@ -1031,30 +1032,14 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper
key_end[0] = '\0';
tmp += op == OP_ASSIGN ? 1 : 2;
- value = skip_leading_chars(tmp, NULL);
+ tmp = skip_leading_chars(tmp, NULL);
+ r = udev_rule_parse_value(tmp, ret_value, line);
+ if (r < 0)
+ return r;
- /* value must be double quotated */
- if (value[0] != '"')
- return -EINVAL;
- value++;
-
- /* unescape double quotation '\"' -> '"' */
- for (i = j = value; ; i++, j++) {
- if (*i == '"')
- break;
- if (*i == '\0')
- return -EINVAL;
- if (i[0] == '\\' && i[1] == '"')
- i++;
- *j = *i;
- }
- j[0] = '\0';
-
- *line = i+1;
*ret_key = key_begin;
*ret_attr = attr;
*ret_op = op;
- *ret_value = value;
return 1;
}