skip to content

Which `docker run` flag grants a container one host device without `--privileged`, and what do its rwm bits mean?

level: middleimportance: nice to knowfreq 24%

answer

  1. Not every device, just this one
  2. Three colon-separated fields on the flag
  3. Read, write, and one more letter
  4. The cgroup rule and the node, both
  5. File ownership on the node still counts

basics

~20 s

--device /dev/ttyUSB0:/dev/ttyUSB0:rwm creates that one node inside the container and adds a matching allow rule to its device cgroup. The trailing letters mean read, write and mknod; drop letters to narrow the grant, for example :r for read-only access.

solid answer

~40 s

By default a container's device cgroup denies everything except a small fixed set — `/dev/null`, `/dev/zero`, `/dev/full`, `/dev/random`, `/dev/urandom`, `/dev/tty`, `/dev/console`, `/dev/ptmx` and `/dev/shm`. `--device host-path:container-path:permissions` creates one extra node inside the container and adds exactly one allow rule for its major:minor number. The permission field is a subset of `rwm`: read, write, and mknod (permission to create a node with that number). `--device /dev/ttyUSB0` alone defaults to `rwm`, so name the narrower set explicitly when the container only needs to read. This is the alternative to `--privileged`, which allows *all* devices along with much else. For devices that appear after start, `--device-cgroup-rule 'c 189:* rmw'` can pre-authorise a whole major number. Remember the node's own ownership and mode still apply, so a non-root container process may also need `--group-add`.

code

bash · 5 lines
bash
docker run -d \
  --device /dev/ttyUSB0:/dev/ttyUSB0:r \
  --user 10001 \
  --group-add 20 \
  sensor-reader:2.1

go deeper

for a junior

Know the flag exists and that it is the alternative to --privileged when a container needs one piece of hardware. Recall the shape --device /dev/x:/dev/x.

for a middle

Explain both halves of what the flag does — a node created in the container and an allow rule in its device cgroup — and what r, w and m each permit, including that omitting them grants all three.

for a senior

Show the operational details: narrowing to :r when only reads are needed, --group-add with a numeric GID so a non-root process can open the node, and why a hot-plugged device is not picked up.

for a principal

Own the policy: which hardware grants are allowed at all, how they are recorded per workload, and why a fleet standard that permits --privileged for hardware access is a standard you have already lost.

## The default: a deny-list you rarely notice Every container starts with a device cgroup that denies access to host devices, plus a small allow-list Docker sets up so that ordinary programs work: `/dev/null`, `/dev/zero`, `/dev/full`, `/dev/random`, `/dev/urandom`, `/dev/tty`, `/dev/console`, `/dev/ptmx` and the `/dev/shm` mount. That is why a container cannot open `/dev/sda` or a serial port even when its process runs as root — the node is absent, and even if it existed the cgroup would refuse the open. This is the confinement that `--privileged` throws away. Among other things, `--privileged` allows every device on the host, which is why the correct answer to "my container needs the USB serial adapter" is never `--privileged`. ## The narrow grant ```bash docker run --device /dev/ttyUSB0:/dev/ttyUSB0:rw reader:2.1 ``` The three colon-separated fields are: the path on the host, the path inside the container (defaults to the same path), and the permissions. The permission string is any subset of: - **r** — read from the device. - **w** — write to the device. - **m** — mknod: create a device node with this major:minor number. Omit the field and Docker grants `rwm`. That default is worth knowing, because a container that only needs to read a sensor gets write access it never asked for unless you spell out `:r`. Dropping `m` is nearly free and removes the ability to conjure fresh nodes for the same device. Mechanically, Docker does two things: it creates the node inside the container's `/dev` with the same major:minor and mode as the host's, and it adds an allow rule for that major:minor to the container's device cgroup. Both are needed — a node without a cgroup rule fails to open, and a rule without a node has nothing to open. ## Devices that are not there yet `--device` resolves the host path at container creation time. A device that appears later — a USB adapter replugged, a dynamically created node — will not be usable, because the container's `/dev` is a private mount that does not track the host. For that case `--device-cgroup-rule` pre-authorises a class of numbers: ```bash docker run --device-cgroup-rule 'c 189:* rmw' -v /dev/bus/usb:/dev/bus/usb usb-tool:1.9 ``` Here `c` is a character device, `189:*` is every minor under that major number, and `rmw` the permissions. Note that the rule authorises; something still has to make the node visible inside the container. This is deliberately a wider grant than a single `--device`, so use it only when a fixed node genuinely will not work. ## Permissions still apply The device cgroup is not the only gate. The node inside the container inherits the host's owner and mode, so a serial port owned `root:dialout 0660` is unreadable to a container process running as an unprivileged UID that is not in that group. The fix is `--group-add` with the numeric GID from the host (group *names* mean nothing across the boundary — the container's `/etc/group` is its own). Reaching for root inside the container instead is the answer that gives back what the grant was meant to contain. ## Where this comes up Serial and USB peripherals on edge hardware, a tun/tap node for a VPN client, a raw block device for a storage benchmark, an FPGA or accelerator node. Accelerators are usually not wired up with raw `--device` at all: a vendor container runtime hook injects the right set of nodes and libraries, because the grant is more than one file. Knowing that distinction — narrow static node via `--device`, vendor hook for accelerator stacks — is the practical takeaway. ## The interview shape This is rarely a screening question. It shows up when the role touches hardware, edge devices or storage, and what is really being tested is whether you reach for `--privileged` as a reflex. The strong answer is short: name the flag, name the three permission bits, mention that the default is all three, and note that the file mode on the node still has to permit the container's user.

  • What is the difference between `--device` and bind-mounting the node with `-v /dev/ttyUSB0:/dev/ttyUSB0`?
    A bind mount makes the node visible but does not add an allow rule to the container's device cgroup, so opening it still fails. `--device` does both: it creates the node with the right major:minor and authorises that number in the cgroup. Reaching for a bind mount and then adding `--privileged` to make it work is the antipattern this flag exists to avoid.
  • A container running as UID 10001 still gets permission denied on a granted device. Why?
    The device cgroup allowed it, but ordinary file permissions did not. The node inside the container carries the host's owner and mode — often `root:dialout 0660` — so an unprivileged UID outside that group is refused. Add the host's numeric GID with `--group-add`; group names do not translate across the boundary because the container has its own `/etc/group`.

saying these in an interview costs you the question

  • Reaches for --privileged to give one device
  • Thinks bind-mounting the node under /dev is sufficient
  • Cannot say what the m in rwm means
  • Assumes the flag defaults to read-only
  • Believes a device hot-plugged later becomes usable automatically
  • Ignores the node's owner and mode inside the container

context