]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Mount over /etc/passwd when building an image and running build script 1923/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 25 Sep 2023 11:57:29 +0000 (13:57 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 25 Sep 2023 12:45:52 +0000 (14:45 +0200)
Various tools parse /etc/passwd, so let's make sure it contains the
expected lines when building an image. Also, when running the build
script, mount over /etc/passwd in the image as various build tools
will also query the current user in /etc/passwd (e.g. the kernel's
build script runs "whoami"). Also add a root entry to the /etc/passwd
we generate so both the user running mkosi and root are covered.

mkosi/__init__.py
mkosi/mounts.py
mkosi/state.py

index 757974d543ba924dd3ca17006f5075ce6824cc6a..6561994d1d478ffa15c5e782a543bcc7960eb694 100644 (file)
@@ -349,7 +349,9 @@ def run_build_script(state: MkosiState) -> None:
         ],
     )
 
-    with complete_step("Running build script…"), mount_build_overlay(state):
+    with complete_step("Running build script…"),\
+         mount_build_overlay(state),\
+         mount_passwd(state.name, state.uid, state.gid, state.root):
         bwrap(
             [state.config.build_script],
             network=state.config.with_network,
@@ -986,7 +988,7 @@ def build_initrd(state: MkosiState) -> Path:
     with complete_step("Building initrd"):
         args, [config] = parse_config(cmdline)
         unlink_output(args, config)
-        build_image(args, config, state.uid, state.gid)
+        build_image(args, config, state.name, state.uid, state.gid)
 
     symlink.symlink_to(config.output_dir / config.output)
 
@@ -1854,12 +1856,12 @@ def normalize_mtime(root: Path, mtime: Optional[int], directory: Optional[Path]
             os.utime(p, (mtime, mtime), follow_symlinks=False)
 
 
-def build_image(args: MkosiArgs, config: MkosiConfig, uid: int, gid: int) -> None:
+def build_image(args: MkosiArgs, config: MkosiConfig, name: str, uid: int, gid: int) -> None:
     manifest = Manifest(config) if config.manifest_format else None
     workspace = tempfile.TemporaryDirectory(dir=config.workspace_dir, prefix=".mkosi-tmp")
 
     with workspace, scopedenv({"TMPDIR" : workspace.name}):
-        state = MkosiState(args, config, Path(workspace.name), uid, gid)
+        state = MkosiState(args, config, Path(workspace.name), name, uid, gid)
         install_package_manager_trees(state)
 
         with mount_base_trees(state):
@@ -2389,6 +2391,7 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
 
         with complete_step(f"Building {config.preset or 'default'} image"),\
             mount_tools(config.tools_tree),\
+            mount_passwd(name, uid, gid),\
             prepend_to_environ_path(config):
 
             # Create these as the invoking user to make sure they're owned by the user running mkosi.
@@ -2402,7 +2405,7 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
                     run(["mkdir", "--parents", p], user=uid, group=gid)
 
             with acl_toggle_build(config, uid):
-                build_image(args, config, uid, gid)
+                build_image(args, config, name, uid, gid)
 
             # Make sure all build outputs that are not directories are owned by the user running mkosi.
             for p in config.output_dir.iterdir():
index f400f29ef2f4eaef8d2179da2655c6ade790c76b..2ef6efc9f0b38e64d19bf1e7a1f0887624282c41 100644 (file)
@@ -132,15 +132,17 @@ def mount_usr(tree: Optional[Path], umount: bool = True) -> Iterator[None]:
 
 
 @contextlib.contextmanager
-def mount_passwd(name: str, uid: int, gid: int, umount: bool = True) -> Iterator[None]:
+def mount_passwd(name: str, uid: int, gid: int, root: Path = Path("/"), umount: bool = True) -> Iterator[None]:
     """
     ssh looks up the running user in /etc/passwd and fails if it can't find the running user. To trick it, we
     mount over /etc/passwd with our own file containing our user in the user namespace.
     """
     with tempfile.NamedTemporaryFile(prefix="mkosi.passwd", mode="w") as passwd:
-        passwd.write(f"{name}:x:{uid}:{gid}:{name}:/bin/sh\n")
+        passwd.write("root:x:0:0:root:/root:/bin/sh\n")
+        if uid != 0:
+            passwd.write(f"{name}:x:{uid}:{gid}:{name}:/home/{name}:/bin/sh\n")
+        passwd.flush()
         os.fchown(passwd.file.fileno(), uid, gid)
 
-        with mount(passwd.name, Path("/etc/passwd"), operation="--bind", umount=umount):
-            passwd.close() # Don't need the file anymore after it's mounted.
+        with mount(passwd.name, root / "etc/passwd", operation="--bind", umount=umount):
             yield
index 949a3f33e9f356a9ab8c09d3e26ca293fbad9fd4..9492fbc3941a83cc19656b16e4daa66f9eb227e7 100644 (file)
@@ -10,10 +10,11 @@ from mkosi.util import umask
 class MkosiState:
     """State related properties."""
 
-    def __init__(self, args: MkosiArgs, config: MkosiConfig, workspace: Path, uid: int, gid: int) -> None:
+    def __init__(self, args: MkosiArgs, config: MkosiConfig, workspace: Path, name: str, uid: int, gid: int) -> None:
         self.args = args
         self.config = config
         self.workspace = workspace
+        self.name = name
         self.uid = uid
         self.gid = gid