From c39a4ab76edb19e448b98cf8c5b1ae9e5661bd37 Mon Sep 17 00:00:00 2001 From: Eduard Tolosa Date: Sat, 7 Nov 2026 01:17:39 -0500 Subject: [PATCH] Document nspawn 3.1.0 - hugo.yaml and reference.md: documented version 3.1.0. - reference.md: --device-cgroup-rule on start, run and create; an app given devices of the host runs without a user namespace. - machines.md: --device-cgroup-rule with a USB device that comes and goes; apps given devices run without a user namespace, booted machines keep theirs; binds of file systems that take no idmapped mount go in as they are. - configuration.md: --device-cgroup-rule among the remembered flags. - networking.md: an app on no network keeps its user namespace unless it is given devices. --- content/en/docs/configuration.md | 3 ++- content/en/docs/machines.md | 35 ++++++++++++++++++++++++-------- content/en/docs/networking.md | 3 ++- content/en/docs/reference.md | 7 ++++--- hugo.yaml | 2 +- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/content/en/docs/configuration.md b/content/en/docs/configuration.md index 35bf07d..8bedfa2 100644 --- a/content/en/docs/configuration.md +++ b/content/en/docs/configuration.md @@ -139,7 +139,8 @@ it is created or started; every one of them is remembered until it is changed: `--no-healthcheck`) on `start`, `run`, `create` and `update`, which changes it on a running machine at once. - `--hostname`, `-u`, `-w`, `--cap-add`, `--cap-drop`, `--privileged`, - `--read-only`, `--tmpfs`, `--shm-size`, `--device`, `--gpus`, `--dns`, + `--read-only`, `--tmpfs`, `--shm-size`, `--device`, `--device-cgroup-rule`, + `--gpus`, `--dns`, `--dns-search`, `--add-host`, `--ulimit`, `--oom-score-adj`, `--stop-signal`, `--stop-timeout`, `--timezone`, `--log-driver`, `--init`, `--sysctl`, `--secret`, `--interface` and `--depends-on` on `start`, `run` and `create`, diff --git a/content/en/docs/machines.md b/content/en/docs/machines.md index c7191b4..285fe32 100644 --- a/content/en/docs/machines.md +++ b/content/en/docs/machines.md @@ -80,8 +80,8 @@ variables and the volumes of the last run: - `--health-cmd` and the other `--health-*` options give it a healthcheck, or replace the image's; see [Healthchecks](#healthchecks). - `--hostname`, `-u`, `-w`, `--cap-add`, `--cap-drop`, `--privileged`, - `--read-only`, `--tmpfs`, `--shm-size`, `--device`, `--dns`, `--dns-search`, - `--add-host`, `--ulimit`, `--oom-score-adj`, `--stop-signal`, + `--read-only`, `--tmpfs`, `--shm-size`, `--device`, `--device-cgroup-rule`, + `--dns`, `--dns-search`, `--add-host`, `--ulimit`, `--oom-score-adj`, `--stop-signal`, `--stop-timeout`, `--init` and `--sysctl` shape the machine further, `--log-driver` says where the program's output goes, and `--timezone` how systemd-nspawn sets @@ -181,7 +181,9 @@ empty value for none, as Go's and Erlang's clients do; libsystemd's and Rust's refuse it. A user namespace cannot join a network namespace that belongs to the host, so an -app on a bridge network runs without one (`PrivateUsers=no`). Capabilities, +app on a bridge network runs without one (`PrivateUsers=no`), and so does an app +given devices of the host on any network, since a device node cannot be idmapped. +Capabilities, seccomp and the other namespaces still apply. Such an app gets the capabilities images need to run as written (CHOWN, DAC_OVERRIDE, FOWNER, FSETID, KILL, MKNOD, NET_BIND_SERVICE, NET_RAW, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT, @@ -292,8 +294,11 @@ sudo nspawn start web -v /srv/www:/usr/share/nginx/html:ro -v pgdata:/var/lib/po `:` is refused. In machines that run with private users (every machine but an app on a bridge -network or in another machine's network), the mount is idmapped, so a file root -writes inside belongs to root on the host, and the other way round. On `mstack` +network, in another machine's network or given devices of the host), the mount is +idmapped, so a file root writes inside belongs to root on the host, and the other +way round. A source on a file system that takes no idmapped mount (overlayfs, +devtmpfs, proc, sysfs, NFS, CIFS, FUSE, tmpfs before Linux 6.3) goes in as it is, +its owners unmapped inside. On `mstack` machines nspawn attaches the volumes from the host right after the machine's init starts, since systemd-nspawn cannot idmap binds under managed user namespaces; that is what @@ -517,9 +522,23 @@ its unit: - `--device HOST[:CONTAINER][:PERMISSIONS]`: a device node of the host, bound into the machine and allowed to its cgroup (`r`, `w`, `m`, each once; `rwm` by default; `/dev/sda:r` is the node at the same place), or a directory such as `/dev/dri`, whose nodes are allowed one by - one. In a machine with private users the node keeps the host's - ownership. A CDI name such as `nvidia.com/gpu=all` takes the devices of a - spec instead; see [GPUs and CDI devices](#gpus-and-cdi-devices). + one. An app given devices of the host runs without a user namespace, so root + inside opens a node as its owner and mode allow; a booted machine keeps its + user namespace, where a node keeps the host's ownership. A CDI name such as + `nvidia.com/gpu=all` takes the devices of a spec instead; see + [GPUs and CDI devices](#gpus-and-cdi-devices). +- `--device-cgroup-rule 'TYPE MAJOR:MINOR PERMISSIONS'` lets the machine's cgroup + open nodes by their numbers, the nodes that appear while it runs included: + + ```shell + sudo nspawn run -d --name flasher -v /dev/bus/usb:/dev/bus/usb \ + --device-cgroup-rule 'c 189:* rwm' --network none IMAGE + ``` + + reaches a USB device that comes and goes, as a flasher's does. A rule for + every minor of a major goes by the device groups the host's `/proc/devices` + names after it at each start (`char-usb_device` for 189), and is refused then + for a major without one; one node goes by its numbers (`c 189:3 rw`). - `--dns` and `--dns-search`: the DNS servers and search domains the machine gets instead of the host's resolvers, in an app's generated `resolv.conf` and in a booted machine's `.network` file. `--add-host HOST:IP` (or `HOST=IP`, for diff --git a/content/en/docs/networking.md b/content/en/docs/networking.md index f3c79ef..f3f8e08 100644 --- a/content/en/docs/networking.md +++ b/content/en/docs/networking.md @@ -335,7 +335,8 @@ namespace. `--network none` sets `Private=yes`: the machine has `lo` and nothing else. Published ports do not apply, and an app that -runs this way keeps its user namespace too. +runs this way keeps its user namespace too, unless it is given devices of the +host. ## container:NAME diff --git a/content/en/docs/reference.md b/content/en/docs/reference.md index 457e429..96ae7c2 100644 --- a/content/en/docs/reference.md +++ b/content/en/docs/reference.md @@ -3,7 +3,7 @@ title: Command reference linkTitle: Reference weight: 10 description: >- - Every command and option of nspawn 3.0.0. + Every command and option of nspawn 3.1.0. --- `nspawn --help` and `nspawn COMMAND --help` list the options; this page @@ -406,7 +406,7 @@ nspawn start NAME [--network NETWORK]... [--network-alias [NETWORK=]NAME]... [-p [--health-start-period DURATION] [--health-start-interval DURATION] [--no-healthcheck] [--hostname NAME] [-u USER[:GROUP]] [-w DIR] [--cap-add CAP]... [--cap-drop CAP]... [--privileged] [--read-only] [--tmpfs PATH[:OPTIONS]]... [--shm-size SIZE] - [--device HOST[:CONTAINER[:rwm]]]... [--dns IP]... [--dns-search DOMAIN]... + [--device HOST[:CONTAINER[:rwm]]]... [--device-cgroup-rule RULE]... [--dns IP]... [--dns-search DOMAIN]... [--add-host HOST:IP]... [--ulimit NAME=SOFT[:HARD]]... [--oom-score-adj N] [--stop-signal SIGNAL] [--stop-timeout SECONDS] [--timezone MODE] [--log-driver DRIVER] [--init] [--sysctl KEY=VALUE]... [--interface IFACE]... [--secret NAME[:TARGET[:MODE[:UID:GID]]]]... @@ -452,7 +452,8 @@ Boots an image as a machine. Every option is remembered for the next start. | `--read-only` | Mount the machine's root read-only; `--read-only=false` takes it back. | | `--tmpfs PATH[:OPTIONS]` | An empty tmpfs at a path inside (`/tmp:size=64m,mode=0700`), 1777 when given without options. One on or below `/run`, a tmpfs of every machine already, is left out with a note. Repeatable; `none` forgets them. | | `--shm-size SIZE` | Size of `/dev/shm`: `64m`, `1g`; `0` for the default. | -| `--device HOST[:CONTAINER[:rwm]]` | A device node of the host for the machine (`/dev/ttyUSB0:/dev/ttyUSB0:rw`), or a directory whose nodes are allowed one by one (`/dev/dri`), or a CDI name (`nvidia.com/gpu=all`) for the devices of the host's specs. Repeatable; `none` forgets them. | +| `--device HOST[:CONTAINER[:rwm]]` | A device node of the host for the machine (`/dev/ttyUSB0:/dev/ttyUSB0:rw`), or a directory whose nodes are allowed one by one (`/dev/dri`), or a CDI name (`nvidia.com/gpu=all`) for the devices of the host's specs. An app given devices of the host runs without a user namespace. Repeatable; `none` forgets them. | +| `--device-cgroup-rule RULE` | A rule of the machine's device cgroup, `TYPE MAJOR:MINOR PERMISSIONS` (`c`, `b` or `a` for both; a number or `*`; `r`, `w`, `m`): every node of a major (`c 189:* rwm`), those that appear while it runs included, by the device groups the host's `/proc/devices` names after it at each start, refused then for a major without one; or one node (`c 189:3 rw`). For a bind of the nodes' directory under `/dev`. Repeatable; `none` forgets them. | | `--gpus REQUEST` | GPUs of the host's CDI specs: `all`, a count, or `'"device=0,1"'`, for the NVIDIA spec's devices (the AMD one when only that is there); `driver=` says which. See [GPUs and CDI devices](/docs/machines/#gpus-and-cdi-devices). Repeatable; `none` forgets them. | | `--dns IP` | DNS server for the machine, instead of the host's. Repeatable; `none` forgets them. | | `--dns-search DOMAIN` | DNS search domain, in an app's `resolv.conf` and a booted machine's `.network` file; 254 characters at most, with a letter among its labels. A trailing dot is dropped and `.` stands for none. Repeatable; `none` forgets them. | diff --git a/hugo.yaml b/hugo.yaml index c2c69e4..308925f 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -53,7 +53,7 @@ params: privacy_policy: /about/#privacy # Version of nspawn the documentation describes. - version: 3.0.0 + version: 3.1.0 archived_version: false # In-page links to open issues and suggest changes.