]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fstab-generator: clear nosuid/nodev/noexec for root=bind: mounts
authorDaan De Meyer <daan@amutable.com>
Wed, 3 Jun 2026 13:54:13 +0000 (13:54 +0000)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 3 Jun 2026 19:21:54 +0000 (20:21 +0100)
A bind mount inherits the mount flags of the file system the source
directory resides on. For root=bind: the source typically lives below
/run/ (e.g. a freshly unpacked tar image in /run/machines/), which is
mounted nosuid,nodev, so those flags propagated to /sysroot and broke
suid binaries (e.g. sudo) and device nodes on the booted system.

Default bind root mounts to dev,suid,exec instead, unless the user
overrides this via rootflags=.

Fixes: https://github.com/systemd/systemd/issues/41352
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
man/systemd-fstab-generator.xml
src/fstab-generator/fstab-generator.c
test/test-fstab-generator/test-22-bind.expected/initrd-root-fs.target.requires/sysroot.mount [new symlink]
test/test-fstab-generator/test-22-bind.expected/initrd-usr-fs.target.requires/sysroot.mount [new symlink]
test/test-fstab-generator/test-22-bind.expected/sysroot.mount [new file with mode: 0644]
test/test-fstab-generator/test-22-bind.input [new file with mode: 0644]

index 8e684b29863d803cf7aa5eed70b4eb85da0f08c2..606dd33068ddb44adfb172e6c088613896f3d915 100644 (file)
 
         <para>Use <literal>bind:…</literal> to bind mount another directory as operating system root
         filesystems (added in v258). Expects an absolute path name referencing an existing directory within the initrd's file
-        hierarchy to boot into.</para>
+        hierarchy to boot into. Since the resulting root file system is supposed to behave like a regular OS
+        root, the bind mount is established with the <option>dev</option>, <option>suid</option> and
+        <option>exec</option> options (i.e. the <option>nodev</option>, <option>nosuid</option> and
+        <option>noexec</option> flags that would otherwise be inherited from the file system the source
+        directory resides on, such as <filename>/run/</filename>, are cleared), unless overridden via
+        <varname>rootflags=</varname>.</para>
 
         <para>Set to <literal>off</literal> to turn off mounting of a root file system.</para>
 
index 2c23d285010276e82313493d8e028cd117eb87d9..f24974be5c8108d1334e469c90e4f939349b75e5 100644 (file)
@@ -1240,6 +1240,26 @@ static int add_sysroot_mount(void) {
                 if (!strextend_with_separator(&combined_options, ",", extra_opts))
                         return log_oom();
 
+        /* A bind mount inherits the mount flags (nosuid, nodev, noexec, …) of the file system the source
+         * directory is located on. The source typically lives below /run/ (e.g. a freshly unpacked tar image
+         * in /run/machines/), which is mounted nosuid,nodev, and these flags would then propagate to our root
+         * file system, breaking suid binaries (e.g. sudo) and device nodes. Since this is supposed to become a
+         * regular OS root file system, default to dev,suid,exec instead, unless the user explicitly requested
+         * otherwise. */
+        if (bind) {
+                static const char* const defaults[] = {
+                        "suid", "suid\0" "nosuid\0",
+                        "dev",  "dev\0"  "nodev\0",
+                        "exec", "exec\0" "noexec\0",
+                        NULL,
+                };
+
+                STRV_FOREACH_PAIR(add, test, defaults)
+                        if (!fstab_test_option(combined_options, *test))
+                                if (!strextend_with_separator(&combined_options, ",", *add))
+                                        return log_oom();
+        }
+
         log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what, strna(fstype), strempty(combined_options));
 
         /* Only honor x-systemd.makefs and .validatefs here, others are not relevant in initrd/not used
diff --git a/test/test-fstab-generator/test-22-bind.expected/initrd-root-fs.target.requires/sysroot.mount b/test/test-fstab-generator/test-22-bind.expected/initrd-root-fs.target.requires/sysroot.mount
new file mode 120000 (symlink)
index 0000000..0c969cd
--- /dev/null
@@ -0,0 +1 @@
+../sysroot.mount
\ No newline at end of file
diff --git a/test/test-fstab-generator/test-22-bind.expected/initrd-usr-fs.target.requires/sysroot.mount b/test/test-fstab-generator/test-22-bind.expected/initrd-usr-fs.target.requires/sysroot.mount
new file mode 120000 (symlink)
index 0000000..0c969cd
--- /dev/null
@@ -0,0 +1 @@
+../sysroot.mount
\ No newline at end of file
diff --git a/test/test-fstab-generator/test-22-bind.expected/sysroot.mount b/test/test-fstab-generator/test-22-bind.expected/sysroot.mount
new file mode 100644 (file)
index 0000000..bcc56c6
--- /dev/null
@@ -0,0 +1,12 @@
+# Automatically generated by systemd-fstab-generator
+
+[Unit]
+Documentation=man:fstab(5) man:systemd-fstab-generator(8)
+SourcePath=/proc/cmdline
+Before=initrd-root-fs.target
+After=imports.target
+
+[Mount]
+What=/run/machines/root
+Where=/sysroot
+Options=rw,bind,suid,dev,exec
diff --git a/test/test-fstab-generator/test-22-bind.input b/test/test-fstab-generator/test-22-bind.input
new file mode 100644 (file)
index 0000000..3e90e36
--- /dev/null
@@ -0,0 +1 @@
+root=bind:/run/machines/root