aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/redirects.js1
-rw-r--r--doc/manual/rl-next/linux-sandbox-consistency.md12
-rw-r--r--doc/manual/src/installation/prerequisites-source.md5
-rw-r--r--meson.build3
-rw-r--r--src/libstore/build/local-derivation-goal.cc18
-rw-r--r--src/libstore/globals.hh23
-rw-r--r--src/libstore/linux/fchmodat2-compat.hh28
-rw-r--r--src/libstore/meson.build1
-rw-r--r--tests/nixos/default.nix4
-rw-r--r--tests/nixos/no-new-privileges/no-sandbox.nix21
-rw-r--r--tests/nixos/no-new-privileges/package.nix8
-rw-r--r--tests/nixos/no-new-privileges/sandbox.nix18
-rw-r--r--tests/nixos/root-in-sandbox/default.nix15
-rw-r--r--tests/nixos/root-in-sandbox/package.nix8
14 files changed, 87 insertions, 78 deletions
diff --git a/doc/manual/redirects.js b/doc/manual/redirects.js
index 436564baa..f270d31a4 100644
--- a/doc/manual/redirects.js
+++ b/doc/manual/redirects.js
@@ -24,7 +24,6 @@ const redirects = {
"chap-writing-nix-expressions": "language/index.html",
"part-command-ref": "command-ref/command-ref.html",
"conf-allow-import-from-derivation": "command-ref/conf-file.html#conf-allow-import-from-derivation",
- "conf-allow-new-privileges": "command-ref/conf-file.html#conf-allow-new-privileges",
"conf-allowed-uris": "command-ref/conf-file.html#conf-allowed-uris",
"conf-allowed-users": "command-ref/conf-file.html#conf-allowed-users",
"conf-auto-optimise-store": "command-ref/conf-file.html#conf-auto-optimise-store",
diff --git a/doc/manual/rl-next/linux-sandbox-consistency.md b/doc/manual/rl-next/linux-sandbox-consistency.md
new file mode 100644
index 000000000..6538362b3
--- /dev/null
+++ b/doc/manual/rl-next/linux-sandbox-consistency.md
@@ -0,0 +1,12 @@
+---
+synopsis: Enforce syscall filtering and no-new-privileges on Linux
+cls: 1063
+category: Breaking Changes
+credits: alois31
+---
+
+In order to improve consistency of the build environment, system call filtering and no-new-privileges are now unconditionally enabled on Linux.
+The `filter-syscalls` and `allow-new-privileges` options which could be used to disable these features under some circumstances have been removed.
+
+In order to support building on architectures without libseccomp support, the option to disable syscall filtering at build time remains.
+However, other uses of this option are heavily discouraged, since it would reduce the security of the sandbox substantially.
diff --git a/doc/manual/src/installation/prerequisites-source.md b/doc/manual/src/installation/prerequisites-source.md
index 8584f295a..88a411b7a 100644
--- a/doc/manual/src/installation/prerequisites-source.md
+++ b/doc/manual/src/installation/prerequisites-source.md
@@ -68,10 +68,7 @@ The most current alternative to this section is to read `package.nix` and see wh
may also work, but ancient versions like the ubiquitous 2.5.4a
won't.
- - The `libseccomp` is used to provide syscall filtering on Linux. This
- is an optional dependency and can be disabled passing a
- `--disable-seccomp-sandboxing` option to the `configure` script (Not
- recommended unless your system doesn't support `libseccomp`). To get
+ - The `libseccomp` is used to provide syscall filtering on Linux. To get
the library, visit <https://github.com/seccomp/libseccomp>.
- On 64-bit x86 machines only, `libcpuid` library
diff --git a/meson.build b/meson.build
index 0d59ff751..16cf80cf4 100644
--- a/meson.build
+++ b/meson.build
@@ -182,6 +182,9 @@ deps += cpuid
# seccomp only makes sense on Linux
seccomp_required = is_linux ? get_option('seccomp-sandboxing') : false
seccomp = dependency('libseccomp', 'seccomp', required : seccomp_required, version : '>=2.5.5')
+if is_linux and not seccomp.found()
+ warning('Sandbox security is reduced because libseccomp has not been found! Please provide libseccomp if it supports your CPU architecture.')
+endif
configdata += {
'HAVE_SECCOMP': seccomp.found().to_int(),
}
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 5c36a3ac2..2a64d7b5c 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -34,7 +34,6 @@
/* Includes required for chroot support. */
#if __linux__
#include <sys/ioctl.h>
-#include "linux/fchmodat2-compat.hh"
#include <net/if.h>
#include <netinet/ip.h>
#include <sys/mman.h>
@@ -44,6 +43,7 @@
#include <sys/prctl.h>
#include <sys/syscall.h>
#if HAVE_SECCOMP
+#include "linux/fchmodat2-compat.hh"
#include <seccomp.h>
#endif
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
@@ -1612,7 +1612,6 @@ void LocalDerivationGoal::chownToBuilder(const Path & path)
void setupSeccomp()
{
#if __linux__
- if (!settings.filterSyscalls) return;
#if HAVE_SECCOMP
scmp_filter_ctx ctx;
@@ -1678,15 +1677,18 @@ void setupSeccomp()
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
throw SysError("unable to add seccomp rule");
- if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, settings.allowNewPrivileges ? 0 : 1) != 0)
+ // Set the NO_NEW_PRIVS prctl flag.
+ // This both makes loading seccomp filters work for unprivileged users,
+ // and is an additional security measure in its own right.
+ if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 1) != 0)
throw SysError("unable to set 'no new privileges' seccomp attribute");
if (seccomp_load(ctx) != 0)
throw SysError("unable to load seccomp BPF program");
#else
- throw Error(
- "seccomp is not supported on this platform; "
- "you can bypass this error by setting the option 'filter-syscalls' to false, but note that untrusted builds can then create setuid binaries!");
+ // Still set the no-new-privileges flag if libseccomp is not available.
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
+ throw SysError("PR_SET_NO_NEW_PRIVS failed");
#endif
#endif
}
@@ -1954,10 +1956,6 @@ void LocalDerivationGoal::runChild()
throw SysError("setuid failed");
setUser = false;
-
- // Make sure we can't possibly gain new privileges in the sandbox
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
- throw SysError("PR_SET_NO_NEW_PRIVS failed");
}
#endif
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 8856d8fae..85789f6b5 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -912,29 +912,6 @@ public:
)"};
#if __linux__
- Setting<bool> filterSyscalls{
- this, true, "filter-syscalls",
- R"(
- Whether to prevent certain dangerous system calls, such as
- creation of setuid/setgid files or adding ACLs or extended
- attributes. Only disable this if you're aware of the
- security implications.
- )"};
-
- Setting<bool> allowNewPrivileges{
- this, false, "allow-new-privileges",
- R"(
- (Linux-specific.) By default, builders on Linux cannot acquire new
- privileges by calling setuid/setgid programs or programs that have
- file capabilities. For example, programs such as `sudo` or `ping`
- will fail. (Note that in sandbox builds, no such programs are
- available unless you bind-mount them into the sandbox via the
- `sandbox-paths` option.) You can allow the use of such programs by
- enabling this option. This is impure and usually undesirable, but
- may be useful in certain scenarios (e.g. to spin up containers or
- set up userspace network interfaces in tests).
- )"};
-
Setting<StringSet> ignoredAcls{
this, {"security.selinux", "system.nfs4_acl", "security.csm"}, "ignored-acls",
R"(
diff --git a/src/libstore/linux/fchmodat2-compat.hh b/src/libstore/linux/fchmodat2-compat.hh
index b05da6786..6ad8a5578 100644
--- a/src/libstore/linux/fchmodat2-compat.hh
+++ b/src/libstore/linux/fchmodat2-compat.hh
@@ -20,18 +20,16 @@
#pragma once
///@file
-#if HAVE_SECCOMP
-# if defined(__alpha__)
-# define NIX_SYSCALL_FCHMODAT2 562
-# elif defined(__x86_64__) && SIZE_MAX == 0xFFFFFFFF // x32
-# define NIX_SYSCALL_FCHMODAT2 1073742276
-# elif defined(__mips__) && defined(__mips64) && defined(_ABIN64) // mips64/n64
-# define NIX_SYSCALL_FCHMODAT2 5452
-# elif defined(__mips__) && defined(__mips64) && defined(_ABIN32) // mips64/n32
-# define NIX_SYSCALL_FCHMODAT2 6452
-# elif defined(__mips__) && defined(_ABIO32) // mips32
-# define NIX_SYSCALL_FCHMODAT2 4452
-# else
-# define NIX_SYSCALL_FCHMODAT2 452
-# endif
-#endif // HAVE_SECCOMP
+#if defined(__alpha__)
+# define NIX_SYSCALL_FCHMODAT2 562
+#elif defined(__x86_64__) && SIZE_MAX == 0xFFFFFFFF // x32
+# define NIX_SYSCALL_FCHMODAT2 1073742276
+#elif defined(__mips__) && defined(__mips64) && defined(_ABIN64) // mips64/n64
+# define NIX_SYSCALL_FCHMODAT2 5452
+#elif defined(__mips__) && defined(__mips64) && defined(_ABIN32) // mips64/n32
+# define NIX_SYSCALL_FCHMODAT2 6452
+#elif defined(__mips__) && defined(_ABIO32) // mips32
+# define NIX_SYSCALL_FCHMODAT2 4452
+#else
+# define NIX_SYSCALL_FCHMODAT2 452
+#endif
diff --git a/src/libstore/meson.build b/src/libstore/meson.build
index 4ccb03df7..98549f6d9 100644
--- a/src/libstore/meson.build
+++ b/src/libstore/meson.build
@@ -210,7 +210,6 @@ libstore = library(
seccomp,
sqlite,
sodium,
- seccomp,
curl,
openssl,
aws_sdk,
diff --git a/tests/nixos/default.nix b/tests/nixos/default.nix
index 354413a7c..5e8bc69ce 100644
--- a/tests/nixos/default.nix
+++ b/tests/nixos/default.nix
@@ -184,7 +184,9 @@ in
symlinkResolvconf = runNixOSTestFor "x86_64-linux" ./symlink-resolvconf.nix;
- rootInSandbox = runNixOSTestFor "x86_64-linux" ./root-in-sandbox;
+ noNewPrivilegesInSandbox = runNixOSTestFor "x86_64-linux" ./no-new-privileges/sandbox.nix;
+
+ noNewPrivilegesOutsideSandbox = runNixOSTestFor "x86_64-linux" ./no-new-privileges/no-sandbox.nix;
broken-userns = runNixOSTestFor "x86_64-linux" ./broken-userns.nix;
diff --git a/tests/nixos/no-new-privileges/no-sandbox.nix b/tests/nixos/no-new-privileges/no-sandbox.nix
new file mode 100644
index 000000000..d952a6862
--- /dev/null
+++ b/tests/nixos/no-new-privileges/no-sandbox.nix
@@ -0,0 +1,21 @@
+let
+ inherit (import ../util.nix) mkNixBuildTest;
+in
+mkNixBuildTest {
+ name = "no-new-privileges-outside-sandbox";
+ extraMachineConfig =
+ { pkgs, ... }:
+ {
+ security.wrappers.ohno = {
+ owner = "root";
+ group = "root";
+ capabilities = "cap_sys_nice=eip";
+ source = "${pkgs.libcap}/bin/getpcaps";
+ };
+ nix.settings = {
+ extra-sandbox-paths = [ "/run/wrappers/bin/ohno" ];
+ sandbox = false;
+ };
+ };
+ expressionFile = ./package.nix;
+}
diff --git a/tests/nixos/no-new-privileges/package.nix b/tests/nixos/no-new-privileges/package.nix
new file mode 100644
index 000000000..55c96bc2e
--- /dev/null
+++ b/tests/nixos/no-new-privileges/package.nix
@@ -0,0 +1,8 @@
+{ runCommand, libcap }:
+runCommand "cant-get-capabilities" { nativeBuildInputs = [ libcap.out ]; } ''
+ if [ "$(/run/wrappers/bin/ohno 2>&1)" != "failed to inherit capabilities: Operation not permitted" ]; then
+ echo "Oh no! We gained capabilities!"
+ exit 1
+ fi
+ touch $out
+''
diff --git a/tests/nixos/no-new-privileges/sandbox.nix b/tests/nixos/no-new-privileges/sandbox.nix
new file mode 100644
index 000000000..e2475555e
--- /dev/null
+++ b/tests/nixos/no-new-privileges/sandbox.nix
@@ -0,0 +1,18 @@
+let
+ inherit (import ../util.nix) mkNixBuildTest;
+in
+mkNixBuildTest {
+ name = "no-new-privileges-in-sandbox";
+ extraMachineConfig =
+ { pkgs, ... }:
+ {
+ security.wrappers.ohno = {
+ owner = "root";
+ group = "root";
+ capabilities = "cap_sys_nice=eip";
+ source = "${pkgs.libcap}/bin/getpcaps";
+ };
+ nix.settings.extra-sandbox-paths = [ "/run/wrappers/bin/ohno" ];
+ };
+ expressionFile = ./package.nix;
+}
diff --git a/tests/nixos/root-in-sandbox/default.nix b/tests/nixos/root-in-sandbox/default.nix
deleted file mode 100644
index 110d83f86..000000000
--- a/tests/nixos/root-in-sandbox/default.nix
+++ /dev/null
@@ -1,15 +0,0 @@
-let
- inherit (import ../util.nix) mkNixBuildTest;
-in mkNixBuildTest {
- name = "root-in-sandbox";
- extraMachineConfig = { pkgs, ... }: {
- security.wrappers.ohno = {
- owner = "root";
- group = "root";
- setuid = true;
- source = "${pkgs.coreutils}/bin/whoami";
- };
- nix.settings.extra-sandbox-paths = ["/run/wrappers/bin"];
- };
- expressionFile = ./package.nix;
-}
diff --git a/tests/nixos/root-in-sandbox/package.nix b/tests/nixos/root-in-sandbox/package.nix
deleted file mode 100644
index a1069160c..000000000
--- a/tests/nixos/root-in-sandbox/package.nix
+++ /dev/null
@@ -1,8 +0,0 @@
-{ runCommand }:
-runCommand "cant-get-root-in-sandbox" {} ''
- if /run/wrappers/bin/ohno; then
- echo "Oh no! We're root in the sandbox!"
- exit 1
- fi
- touch $out
-''