]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Don't use overlayfs for /etc and /opt in sandbox
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 27 Sep 2024 10:27:21 +0000 (12:27 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 28 Sep 2024 10:34:45 +0000 (12:34 +0200)
Unprivileged overlayfs isn't available everywhere (see #3054). So
let's try to accomodate this a little by not using overlayfs for /etc
and /opt from the sandbox tree and instead mounting them read-only
into the sandbox. If required, scripts can still mount an overlayfs
onto these if needed, we just don't do it by default anymore.

This does mean we need to set up /etc with mountpoints and symlinks
beforehand in install_sandbox_trees(), but this shouldn't be a huge
problem.

mkosi/__init__.py
mkosi/mounts.py
mkosi/run.py

index ba5d31d2e4a5eedad33bd2305391ae5cf7ba2db0..a0d2cb96cb454ff2fdcd9ffa4cfb292321a0e23d 100644 (file)
@@ -1067,11 +1067,6 @@ def install_sandbox_trees(config: Config, dst: Path) -> None:
     # Ensure /etc exists in the sandbox
     (dst / "etc").mkdir(exist_ok=True)
 
-    if Path("/etc/passwd").exists():
-        shutil.copy("/etc/passwd", dst / "etc/passwd")
-    if Path("/etc/group").exists():
-        shutil.copy("/etc/passwd", dst / "etc/group")
-
     if (p := config.tools() / "etc/crypto-policies").exists():
         copy_tree(
             p,
@@ -1081,12 +1076,46 @@ def install_sandbox_trees(config: Config, dst: Path) -> None:
             sandbox=config.sandbox,
         )  # fmt: skip
 
-    if not config.sandbox_trees:
-        return
+    if config.sandbox_trees:
+        with complete_step("Copying in sandbox trees…"):
+            for tree in config.sandbox_trees:
+                install_tree(config, tree.source, dst, target=tree.target, preserve=False)
 
-    with complete_step("Copying in sandbox trees…"):
-        for tree in config.sandbox_trees:
-            install_tree(config, tree.source, dst, target=tree.target, preserve=False)
+    if Path("/etc/passwd").exists():
+        shutil.copy("/etc/passwd", dst / "etc/passwd")
+    if Path("/etc/group").exists():
+        shutil.copy("/etc/passwd", dst / "etc/group")
+
+    if not (dst / "etc/mtab").is_symlink():
+        (dst / "etc/mtab").symlink_to("../proc/self/mounts")
+
+    Path(dst / "etc/resolv.conf").unlink(missing_ok=True)
+    Path(dst / "etc/resolv.conf").touch()
+
+    Path(dst / "etc/static").unlink(missing_ok=True)
+    if (config.tools() / "etc/static").is_symlink():
+        (dst / "etc/static").symlink_to((config.tools() / "etc/static").readlink())
+
+    # Create various mountpoints in /etc as /etc from the sandbox tree is mounted read-only into the sandbox.
+
+    for d in (
+        "etc/pki",
+        "etc/ssl",
+        "etc/ca-certificates",
+        "var/lib/ca-certificates",
+        "etc/pacman.d/gnupg",
+        "etc/alternatives",
+    ):
+        (dst / d).mkdir(parents=True, exist_ok=True)
+
+    for f in (
+        "etc/passwd",
+        "etc/group",
+        "etc/shadow",
+        "etc/gshadow",
+        "etc/ld.so.cache",
+    ):
+        (dst / f).touch(exist_ok=True)
 
 
 def install_package_directories(context: Context, directories: Sequence[Path]) -> None:
index 3c843db307904a6eeee892755bb7fbfd3d530cc9..966f0aa2f256eb5e9dcb6a54496c4c2c96c95a18 100644 (file)
@@ -95,7 +95,6 @@ def finalize_crypto_mounts(config: Config) -> list[PathString]:
             Path("etc/pki"),
             Path("etc/ssl"),
             Path("etc/ca-certificates"),
-            Path("etc/static"),
             Path("var/lib/ca-certificates"),
         )
         if (root / subdir).exists()
@@ -105,7 +104,4 @@ def finalize_crypto_mounts(config: Config) -> list[PathString]:
     if (config.tools() / "etc/pacman.d/gnupg").exists():
         mounts += [(config.tools() / "etc/pacman.d/gnupg", Path("/etc/pacman.d/gnupg"))]
 
-    return flatten(
-        ("--symlink", src.readlink(), target) if src.is_symlink() else ("--ro-bind", src, target)
-        for src, target in sorted(set(mounts), key=lambda s: s[1])
-    )
+    return flatten(("--ro-bind", src, target) for src, target in sorted(set(mounts), key=lambda s: s[1]))
index ff0afcea152fbe1332053b06b3957f170d0ad75e..ca39ce36ae06d36690032e06e6e1ed837d72c581 100644 (file)
@@ -538,7 +538,6 @@ def sandbox_cmd(
             "--dir", "/var/tmp",
             "--dir", "/var/log",
             "--unshare-ipc",
-            "--symlink", "../proc/self/mounts", "/etc/mtab",
         ]  # fmt: skip
 
         if devices:
@@ -566,7 +565,13 @@ def sandbox_cmd(
             yield [*cmdline, "--bind", tmp, "/var/tmp", *options, "--"]
             return
 
-        for d in ("etc", "opt", "srv", "media", "mnt", "var", "run", "tmp"):
+        for d in ("etc", "opt"):
+            if overlay and (overlay / d).exists():
+                cmdline += ["--ro-bind", overlay / d, Path("/") / d]
+            else:
+                cmdline += ["--dir", Path("/") / d]
+
+        for d in ("srv", "media", "mnt", "var", "run", "tmp"):
             tmp = None
             if d not in ("run", "tmp"):
                 with umask(~0o755):