]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Use passwd symlinks instead of bind mounts
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 15 Nov 2024 15:24:18 +0000 (16:24 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 17 Nov 2024 16:29:49 +0000 (17:29 +0100)
Bind mounts don't reflect changes to the original files if they're
replaced instead of modified. Let's use symlinks instead so that
changes to the original files are always reflected.

Fixes #3189

mkosi/__init__.py
mkosi/archive.py
mkosi/installer/__init__.py
mkosi/run.py

index b9f99aafb76f82494a98600c98c8fa9093a94bed..9c6d92a417d065b86f624b9113133d4dfa7aa6ce 100644 (file)
@@ -103,7 +103,7 @@ from mkosi.run import (
     chroot_cmd,
     chroot_options,
     finalize_interpreter,
-    finalize_passwd_mounts,
+    finalize_passwd_symlinks,
     fork_and_wait,
     run,
     workdir,
@@ -2822,9 +2822,8 @@ def run_tmpfiles(context: Context) -> None:
                 options=[
                     "--bind", context.root, "/buildroot",
                     # systemd uses acl.h to parse ACLs in tmpfiles snippets which uses the host's
-                    # passwd so we have to mount the image's passwd over it to make ACL parsing
-                    # work.
-                    *finalize_passwd_mounts(context.root),
+                    # passwd so we have to symlink the image's passwd to make ACL parsing work.
+                    *finalize_passwd_symlinks("/buildroot"),
                     # Sometimes directories are configured to be owned by root in tmpfiles snippets
                     # so we want to make sure those chown()'s succeed by making ourselves the root
                     # user so that the root user exists.
index b735955bfb287c516ecd9fcb659b25e8d6f177f5..5b5b6ea91e17797d9b2c4bf380b680e0d4e3d8d8 100644 (file)
@@ -6,7 +6,7 @@ from pathlib import Path
 from typing import Optional
 
 from mkosi.log import log_step
-from mkosi.run import SandboxProtocol, finalize_passwd_mounts, nosandbox, run, workdir
+from mkosi.run import SandboxProtocol, finalize_passwd_symlinks, nosandbox, run, workdir
 from mkosi.sandbox import umask
 from mkosi.types import PathString
 from mkosi.util import chdir
@@ -51,7 +51,7 @@ def make_tar(src: Path, dst: Path, *, sandbox: SandboxProtocol = nosandbox) -> N
             # Make sure tar uses user/group information from the root directory instead of the host.
             sandbox=sandbox(
                 binary="tar",
-                options=["--ro-bind", src, workdir(src), *finalize_passwd_mounts(src)],
+                options=["--ro-bind", src, workdir(src), *finalize_passwd_symlinks(workdir(src))],
             ),
         )  # fmt: skip
 
@@ -98,7 +98,7 @@ def extract_tar(
             options=[
                 "--ro-bind", src, workdir(src),
                 "--bind", dst, workdir(dst),
-                *finalize_passwd_mounts(dst),
+                *finalize_passwd_symlinks(workdir(dst)),
             ],
         ),
     )  # fmt: skip
@@ -136,6 +136,6 @@ def make_cpio(
             stdout=f,
             sandbox=sandbox(
                 binary="cpio",
-                options=["--ro-bind", src, workdir(src), *finalize_passwd_mounts(src)],
+                options=["--ro-bind", src, workdir(src), *finalize_passwd_symlinks(workdir(src))],
             ),
         )  # fmt: skip
index 832f11f229b3fad2e3d1e826d0d1a53bd0bfab9a..fc971342007ebee4f651140390ec5043b2037928 100644 (file)
@@ -7,7 +7,7 @@ from pathlib import Path
 from mkosi.config import Config, ConfigFeature, OutputFormat
 from mkosi.context import Context
 from mkosi.mounts import finalize_crypto_mounts
-from mkosi.run import apivfs_options, finalize_interpreter, finalize_passwd_mounts, find_binary
+from mkosi.run import apivfs_options, finalize_interpreter, finalize_passwd_symlinks, find_binary
 from mkosi.tree import rmtree
 from mkosi.types import PathString
 from mkosi.util import flatten, startswith
@@ -109,10 +109,9 @@ class PackageManager:
             "--suppress-chown",
             # Make sure /etc/machine-id is not overwritten by any package manager post install scripts.
             "--ro-bind-try", Path(root) / "etc/machine-id", "/buildroot/etc/machine-id",
-            # If we're already in the sandbox, we want to pick up use the passwd files from /buildroot since
-            # the original root won't be available anymore. If we're not in the sandbox yet, we want to pick
-            # up the passwd files from the original root.
-            *finalize_passwd_mounts(root),
+            # Some package managers (e.g. dpkg) read from the host's /etc/passwd instead of the buildroot's
+            # /etc/passwd so we symlink /etc/passwd from the buildroot to make sure it gets used.
+            *(finalize_passwd_symlinks("/buildroot") if apivfs else []),
         ]  # fmt: skip
 
     @classmethod
index 8c507655d30162fec7a5e0c6df95f614bb0e6640..b777fffb733d239aed81345a01efe19f78f9b0d9 100644 (file)
@@ -415,15 +415,14 @@ def workdir(path: Path, sandbox: Optional[SandboxProtocol] = None) -> str:
     return joinpath(subdir, str(path))
 
 
-def finalize_passwd_mounts(root: PathString) -> list[PathString]:
+def finalize_passwd_symlinks(root: PathString) -> list[PathString]:
     """
     If passwd or a related file exists in the apivfs directory, bind mount it over the host files while we
     run the command, to make sure that the command we run uses user/group information from the apivfs
     directory instead of from the host.
     """
     return flatten(
-        ("--ro-bind-try", Path(root) / "etc" / f, f"/etc/{f}")
-        for f in ("passwd", "group", "shadow", "gshadow")
+        ("--symlink", Path(root) / "etc" / f, f"/etc/{f}") for f in ("passwd", "group", "shadow", "gshadow")
     )