Skip to content
LinuxDeep Dive Published Updated 6 min readViews unavailable

How udev and the Device Model Actually Discover and Name Hardware

Trace Linux hardware from kernel device registration through sysfs, uevents, devtmpfs and udev rules to stable, collision-tested user-facing links.

Linux device appearance is a distributed pipeline. A bus/driver discovers hardware, the kernel device model creates objects and attributes in sysfs, the kernel emits a uevent, devtmpfs can create the basic device node, and the udev manager applies userspace policy such as permissions, tags, properties, and stable symlinks.

udev does not make every identifier stable, and it is inaccurate on modern systems to say userspace alone creates all /dev nodes.

The kernel registers an object graph

Devices participate in buses, classes, drivers, parents/children, power-management and firmware relationships represented by kobjects. sysfs exposes that graph through directories, attributes, and symlinks. A class path is a convenient view, not necessarily the physical topology:

readlink -f /sys/class/tty/ttyUSB0/device
udevadm info --attribute-walk --name=/dev/ttyUSB0

Hot unplug can remove the target during inspection. Record the uevent path and properties atomically where possible rather than assuming a path persists.

Kernel names are necessary but not persistent policy

Drivers assign kernel names such as sda, ttyUSB0, or video0 according to subsystem rules and enumeration. Concurrent probing, changed topology, added hardware, driver changes, and boot timing can alter order. Some names are stable within a topology; none should be generalized without subsystem guarantees.

Userspace normally cannot arbitrarily rename block/character device nodes. It creates predictable symlinks and, for supported subsystems such as network interfaces, can request a kernel-visible rename under specific rules.

devtmpfs provides baseline nodes

With devtmpfs, the kernel creates device nodes using registered major/minor numbers, often before userspace policy completes. systemd-udevd then changes permissions/ownership, creates links, imports properties, triggers services, and performs other configured actions.

This split explains why a node can briefly exist before its final links/permissions, and why software should wait for udev initialization rather than polling for /dev/sdX and immediately acting.

Uevents carry action and environment

Kernel kobjects emit events such as add, remove, change, move, bind, or unbind with subsystem/device-path properties. systemd-udevd receives and orders work with subsystem/device dependencies, but independent devices can process concurrently.

Observe on a test host:

udevadm monitor --kernel --udev --property

This may expose serials, paths, network attributes, and device identifiers. Do not capture unrelated production hotplug traffic into public logs.

Rules match events and assign policy

Rules are comma-separated match and assignment tokens loaded from vendor/runtime/local directories in lexical order with precedence. == matches; =/+=/:= assign with different semantics. Keys such as SUBSYSTEM, KERNEL, ENV, ATTR, and ATTRS refer to different event/device/parent data.

Multiple parent-match keys in one rule must resolve consistently according to udev’s parent matching rules. A value found somewhere in attribute-walk is not enough if the rule combines incompatible parent levels.

A serial-device rule needs unique evidence

Vendor/product IDs identify a model, not one physical unit. A safe stable link should incorporate a trustworthy unique serial or physical port policy where available:

SUBSYSTEM=="tty", KERNEL=="ttyUSB*", \
  ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
  ATTRS{serial}=="A1B2C3D4", \
  SYMLINK+="serial/by-purpose/lab-console"

Treat this as a pattern to adapt, not a copy-ready rule. Verify the actual attribute path/value, duplicates, allowed characters, ownership/group policy, and whether the USB bridge reports a real serial. Two matches competing for one symlink produce unstable ownership.

Rule filenames and precedence matter

Local rules belong under /etc/udev/rules.d, not edited vendor files under /usr/lib. A same-named local file can override vendor content; lexical numbers influence processing order but assignments can be finalized or appended depending on operators.

Inspect loaded rules and document why a high-numbered override is required. Broad MODE="0666" or OWNER= rules create local privilege problems. Prefer a dedicated group, logind uaccess tag when appropriate to the seat model, and least access.

  • /dev/disk/by-id aims at device-provided/model/serial identity, but bridges/firmware can omit or duplicate values.
  • by-path identifies connection topology and changes when moving ports.
  • by-uuid identifies filesystem UUID, changes on reformat, and can collide after cloning.
  • by-partuuid identifies partition-table UUID and can also duplicate after disk imaging.
  • filesystem labels are administrator-friendly but not inherently unique.

Choose the identity that matches the operation. Mounting one filesystem, replacing a physical drive, and addressing a fixed bay require different semantics. Validate duplicates before boot/storage changes.

fstab resolution is broader than udev

mount/libblkid/systemd generators can resolve UUID=, PARTUUID=, labels, or paths into devices. udev commonly supplies links/properties, but saying udev “guarantees fstab UUID” oversimplifies the stack.

Before editing fstab, use findmnt --verify, blkid, lsblk -f, initramfs/boot requirements, and an out-of-band recovery path. Never infer the root disk from sda.

Test rules without claiming zero side effects

udevadm test simulates an event through the rules engine and prints debug output, but rules can include programs/imports and the simulated environment is not identical to a live event. Use a VM/disposable device and inspect the exact sysfs path:

udevadm test --action=add /sys/class/tty/ttyUSB0

Check the installed udev version’s manual. Do not test storage-removal, network rename, or RUN behavior on production merely because the command is called “test.”

Reload does not reprocess existing devices

udevadm control --reload reloads rules for future events. udevadm trigger synthesizes events and is an active state change that can rerun rules across many devices. A broad trigger can rename interfaces, alter permissions, start units, or invoke helpers.

Target one authorized sysfs object in a maintenance window, use udevadm settle only with understood timeout/queue semantics, and verify no unrelated event is pending. Physical replug may be safer for one lab peripheral.

Long-running work does not belong in a rule

udev event workers must finish quickly; long-running processes can be killed and block device event handling. RUN has strict restrictions and should not launch daemons or network-heavy scripts. Use tags/properties such as SYSTEMD_WANTS to ask the service manager to start a bounded unit when the device is active, with appropriate dependencies and sandboxing.

Never interpolate untrusted device properties into a shell command. Execute fixed binaries with validated arguments and no implicit shell.

Permissions, containers, and seats complicate visibility

Device cgroups, mount namespaces, container runtimes, logind seat ACLs, SELinux/AppArmor, and capabilities can deny a node even when its Unix mode appears open. Conversely, passing a device into a container can grant powerful ioctls beyond simple read/write.

Audit major/minor, symlink target, ACL, LSM label, device-cgroup rule, namespace mount, driver, and allowed ioctls. Do not fix access with chmod 777.

Build an acceptance matrix

Test cold boot, repeated unplug/replug, reversed plug order, two identical models, missing/duplicate serial, port move, hub insertion, suspend/resume, rule reload, package update, and device removal while open. Confirm symlink target, collision behavior, permissions, consumer service start/stop, and rollback.

The policy is reliable when it identifies the intended property (unit vs port vs filesystem), never points two devices at one critical link, does not execute untrusted data, and removal leaves no stale service assumption.

Related:

Sources:

Comments