]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Stop copying the cached build overlay
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 19 Apr 2023 08:20:30 +0000 (10:20 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 19 Apr 2023 10:33:35 +0000 (12:33 +0200)
The build overlay is not modified during the final build, it's only
used to run the build script which cannot touch the build image. Let's
enforce this even more by mounting the build overlay read-only when
running the script.

With this assurance, we can stop copying the cached build overlay every
time and just use it directly since we're certain it cannot be modified
anyway.

mkosi/__init__.py
mkosi/mounts.py

index 6a07c90b0e4f9c83ac43ae4e66e882e59ddd9ec7..26a307576b2beb2d51c85db23a713cb1a3cc9154 100644 (file)
@@ -290,6 +290,13 @@ def install_build_packages(state: MkosiState, cached: bool) -> None:
     with mount_build_overlay(state):
         state.installer.install_packages(state, state.config.build_packages)
 
+        # Create a few necessary mount points inside the build overlay for later.
+        state.root.joinpath("work").mkdir(mode=0o755)
+        state.root.joinpath("work/src").mkdir(mode=0o755)
+        state.root.joinpath("work/dest").mkdir(mode=0o755)
+        state.root.joinpath("work/build-script").touch(mode=0o755)
+        state.root.joinpath("work/build").mkdir(mode=0o755)
+
 
 def remove_packages(state: MkosiState) -> None:
     """Remove packages listed in config.remove_packages"""
@@ -379,8 +386,8 @@ def configure_autologin(state: MkosiState) -> None:
 
 
 
-def mount_build_overlay(state: MkosiState) -> ContextManager[Path]:
-    return mount_overlay(state.root, state.build_overlay, state.workdir, state.root)
+def mount_build_overlay(state: MkosiState, read_only: bool = False) -> ContextManager[Path]:
+    return mount_overlay(state.root, state.build_overlay, state.workdir, state.root, read_only)
 
 
 def run_prepare_script(state: MkosiState, cached: bool, build: bool) -> None:
@@ -1645,8 +1652,8 @@ def reuse_cache_tree(state: MkosiState) -> bool:
         copy_path(final, state.root)
         acl_toggle_remove(state.config, state.root, state.uid, allow=False)
         if state.config.build_script:
-            copy_path(build, state.build_overlay)
-            acl_toggle_remove(state.config, state.build_overlay, state.uid, allow=False)
+            state.build_overlay.rmdir()
+            state.build_overlay.symlink_to(build)
 
     return True
 
@@ -1802,14 +1809,10 @@ def run_build_script(state: MkosiState) -> None:
     if state.config.build_script is None or state.for_cache:
         return
 
-    with complete_step("Running build script…"), mount_build_overlay(state):
-        # Bubblewrap creates bind mount point parent directories with restrictive permissions so we create
-        # the work directory ourselves here.
-        state.root.joinpath("work").mkdir(mode=0o755)
-
+    with complete_step("Running build script…"), mount_build_overlay(state, read_only=True):
         bwrap: list[PathString] = [
             "--bind", state.config.build_sources, "/work/src",
-            "--bind", state.config.build_script, f"/work/{state.config.build_script.name}",
+            "--bind", state.config.build_script, "/work/build-script",
             "--bind", install_dir(state), "/work/dest",
             "--chdir", "/work/src",
         ]
@@ -1826,7 +1829,7 @@ def run_build_script(state: MkosiState) -> None:
             bwrap += ["--bind", state.config.build_dir, "/work/build"]
             env |= dict(BUILDDIR="/work/build")
 
-        cmd = ["setpriv", f"--reuid={state.uid}", f"--regid={state.gid}", "--clear-groups", f"/work/{state.config.build_script.name}"]
+        cmd = ["setpriv", f"--reuid={state.uid}", f"--regid={state.gid}", "--clear-groups", "/work/build-script"]
         # When we're building the image because it's required for another verb, any passed arguments are
         # most likely intended for the target verb, and not for "build", so don't add them in that case.
         if state.config.verb == Verb.build:
@@ -1837,12 +1840,6 @@ def run_build_script(state: MkosiState) -> None:
         run_workspace_command(state, cmd, network=state.config.with_network, bwrap_params=bwrap,
                               stdout=sys.stdout, env=env)
 
-        state.root.joinpath("work/dest").rmdir()
-        state.root.joinpath("work/src").rmdir()
-        state.root.joinpath("work/build").rmdir()
-        state.root.joinpath("work").joinpath(state.config.build_script.name).unlink()
-        state.root.joinpath("work").rmdir()
-
 
 def need_cache_tree(state: MkosiState) -> bool:
     if not state.config.incremental:
index ad1c9deaa07de7cd0de09fef697b9be50817a820..66df4ea3a5953a11ac6c792d08a97ea9f15830a5 100644 (file)
@@ -89,7 +89,8 @@ def mount_overlay(
     lower: Path,
     upper: Path,
     workdir: Path,
-    where: Path
+    where: Path,
+    read_only: bool = True,
 ) -> Iterator[Path]:
     options = [f"lowerdir={lower}", f"upperdir={upper}", f"workdir={workdir}"]
 
@@ -98,7 +99,7 @@ def mount_overlay(
         options.append("userxattr")
 
     try:
-        with mount("overlay", where, options=options, type="overlay"):
+        with mount("overlay", where, options=options, type="overlay", read_only=read_only):
             yield where
     finally:
         with complete_step("Cleaning up overlayfs"):