diff --git a/packages/marmel/landlock-nix-store.patch b/packages/marmel/landlock-nix-store.patch new file mode 100644 index 0000000..5ca62e1 --- /dev/null +++ b/packages/marmel/landlock-nix-store.patch @@ -0,0 +1,29 @@ +--- a/src/harness/sandbox.rs ++++ b/src/harness/sandbox.rs +@@ -414,8 +414,25 @@ + } + + // 5. System toolchains, device nodes, runtime files (DNS /run/systemd/resolve), and binaries (Read-Only + Execute) ++ // ++ // On NixOS and Guix /bin, /usr/bin and /lib are symlink farms: every executable ++ // resolves below the package store, and Landlock matches the resolved target rather ++ // than the symlinked view, so the store has to be listed here or nothing can be exec'd ++ // at all. Store paths are world-readable by design, so read+execute there adds no ++ // reach that a local user does not already have. + let ro_paths = [ +- "/usr", "/bin", "/lib", "/lib64", "/opt", "/etc", "/dev", "/proc", "/sys", "/run", "/var", ++ "/usr", ++ "/bin", ++ "/lib", ++ "/lib64", ++ "/opt", ++ "/etc", ++ "/dev", ++ "/proc", ++ "/sys", ++ "/run", ++ "/var", ++ "/nix/store", + ]; + for p in ro_paths { + if Path::new(p).exists() diff --git a/packages/marmel/package.nix b/packages/marmel/package.nix index 9c440a1..83c4c9a 100644 --- a/packages/marmel/package.nix +++ b/packages/marmel/package.nix @@ -23,7 +23,14 @@ rustPlatform.buildRustPackage rec { nativeCheckInputs = [ cacert ]; - patches = [ ./session-boot-trust-store.patch ]; + patches = [ + ./session-boot-trust-store.patch + # Temporary downstream fix, upstream has no NixOS-aware allow-list yet. + # Adds "/nix/store" to the read-only+execute list of the Landlock ruleset, so the + # sandbox re-entry can exec `sh` on a Nix host at all. Drop when upstream lands it + # (nix-overlay-5ml). + ./landlock-nix-store.patch + ]; # The test suite builds `reqwest::Client`s, and rustls rejects construction # outright when no system trust store is found ("No CA certificates were @@ -44,27 +51,17 @@ rustPlatform.buildRustPackage rec { # then 1 failure, then 0 with serial threads. Drop this flag once upstream # makes that state per-instance. # - # The two sandbox-exec tests are skipped. They re-exec `sh` through - # `marmel --internal-sandbox-exec`, and apply_landlock_linux() allow-lists - # FHS paths only (/usr, /bin, /lib, /opt, /etc, /var) plus /tmp. Landlock - # matches inodes rather than symlinked views, and every binary on NixOS - # resolves into the store (`/bin/sh` is - # /nix/store/-bash-interactive-5.3p9/bin/bash), so the exec is denied: - # "Failed to exec shell in sandbox: Permission denied (os error 13)". Checked - # against this build on a NixOS host, where the same command succeeds once - # the workspace root is `/` and therefore covers /nix/store. Inside the build - # sandbox the tests are doubly impossible: /usr, /lib, /run and /var do not - # exist, so the `if let Ok(fd)` guards silently drop those rules, and - # /etc/resolv.conf is absent because the sandbox has no network. 342 of 344 - # tests still run. Upstream main still carries the FHS-only list; drop these - # skips if that ever gains /nix/store. + # Only the DNS sandbox-exec test is skipped now. It re-execs `sh` through + # `marmel --internal-sandbox-exec` and then reads /etc/resolv.conf, which the + # no-network build sandbox does not provide. landlock-nix-store.patch fixed the + # exec half for both sandbox-exec tests: with it, the cross-directory rename + # test runs for real (no SKIP printed by `integration_host`) and the lib suite + # passes at 966 tests with that single filter. cargoTestFlags = [ "--" "--test-threads=1" "--skip" "harness::sandbox::tests::test_internal_sandbox_exec_dev_null_and_dns" - "--skip" - "harness::sandbox::tests::test_internal_sandbox_cross_directory_rename" ]; # Role prompts are embedded with `include_str!`, so the binary needs no