From: Daan De Meyer Date: Fri, 15 Nov 2024 15:24:18 +0000 (+0100) Subject: Use passwd symlinks instead of bind mounts X-Git-Tag: v25~167^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=04cd6d1434aa5dd5dea4ab360ce03dd1958dc403;p=thirdparty%2Fmkosi.git Use passwd symlinks instead of bind mounts 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 --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index b9f99aafb..9c6d92a41 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -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. diff --git a/mkosi/archive.py b/mkosi/archive.py index b735955bf..5b5b6ea91 100644 --- a/mkosi/archive.py +++ b/mkosi/archive.py @@ -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 diff --git a/mkosi/installer/__init__.py b/mkosi/installer/__init__.py index 832f11f22..fc9713420 100644 --- a/mkosi/installer/__init__.py +++ b/mkosi/installer/__init__.py @@ -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 diff --git a/mkosi/run.py b/mkosi/run.py index 8c507655d..b777fffb7 100644 --- a/mkosi/run.py +++ b/mkosi/run.py @@ -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") )