From 4319dc58eb7cbd94398ca1b165fec86242e7f971 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 27 Jan 2024 09:49:51 +0000 Subject: [PATCH] programs: landlock: restrict the capabilities of sandboxed processes --- modules/programs/sane-sandboxed | 22 ++++++++++++++++++++-- modules/programs/sane-sandboxed.nix | 3 ++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/modules/programs/sane-sandboxed b/modules/programs/sane-sandboxed index 0a2c8866..5d687af7 100644 --- a/modules/programs/sane-sandboxed +++ b/modules/programs/sane-sandboxed @@ -17,6 +17,7 @@ method= firejailFlags=() bwrapFlags=() landlockPaths= +landlockCapshCapsArg= debug() { [ -n "$isDebug" ] && printf "[debug] %s" "$1" >&2 @@ -261,7 +262,16 @@ landlockIngestProfile() { debug "landlock doesn't implement profiles" } landlockIngestCapability() { - debug "landlock doesn't implement capabilities" + # N.B. `capsh` parsing of `--caps=X` arg is idiosyncratic: + # - valid: `capsh --caps=CAP_FOO,CAP_BAR=eip -- ` + # - valid: `capsh --caps= -- ` + # - invalid: `capsh --caps=CAP_FOO,CAP_BAR -- ` + # - invalid: `capsh --caps==eip -- ` + if [ -z "$landlockCapshCapsArg" ]; then + landlockCapshCapsArg="cap_$1=eip" + else + landlockCapshCapsArg="cap_$1,$landlockCapshCapsArg" + fi } landlockExec() { # other sandboxing methods would create fake /dev, /proc, /tmp filesystems @@ -285,7 +295,15 @@ landlockExec() { # landlockIngestRootPath '/dev/stderr' # landlockIngestRootPath '/dev/stdin' # landlockIngestRootPath '/dev/stdout' - PATH="$PATH:@landlockSandboxer@/bin" LL_FS_RO= LL_FS_RW="$landlockPaths" exec sandboxer "${cliArgs[@]}" + + # landlock sandboxer has no native support for capabilities (except that it sets nonewprivs), + # so trampoline through `capsh` as well, to drop privs. + # N.B: capsh passes its arg to bash (via /nix/store/.../bash), which means you have to `-c "my command"` to + # invoke the actual user command. + PATH="$PATH:@landlockSandboxer@/bin:@libcap@/bin" LL_FS_RO= LL_FS_RW="$landlockPaths" exec \ + sandboxer \ + capsh "--caps=$landlockCapshCapsArg" -- \ + -c "${cliArgs[*]}" } diff --git a/modules/programs/sane-sandboxed.nix b/modules/programs/sane-sandboxed.nix index 570f1eb1..f78a3201 100644 --- a/modules/programs/sane-sandboxed.nix +++ b/modules/programs/sane-sandboxed.nix @@ -2,6 +2,7 @@ , bubblewrap , firejail , landlock-sandboxer +, libcap , runtimeShell , substituteAll , profileDir ? "/share/sane-sandboxed/profiles" @@ -10,7 +11,7 @@ let sane-sandboxed = substituteAll { src = ./sane-sandboxed; - inherit bubblewrap firejail runtimeShell; + inherit bubblewrap firejail libcap runtimeShell; landlockSandboxer = landlock-sandboxer; firejailProfileDirs = "/run/current-system/sw/etc/firejail /etc/firejail ${firejail}/etc/firejail"; # /run might be unavailable inside a container, so to support nested containers