diff options
-rw-r--r-- | Makefile.config.in | 1 | ||||
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | release.nix | 7 | ||||
-rw-r--r-- | src/libstore/build.cc | 94 | ||||
-rw-r--r-- | src/libstore/local.mk | 4 | ||||
-rw-r--r-- | tests/sandbox.nix | 54 |
6 files changed, 30 insertions, 139 deletions
diff --git a/Makefile.config.in b/Makefile.config.in index 08408ea5f..a03776d57 100644 --- a/Makefile.config.in +++ b/Makefile.config.in @@ -10,7 +10,6 @@ OPENSSL_LIBS = @OPENSSL_LIBS@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ SODIUM_LIBS = @SODIUM_LIBS@ -LIBSECCOMP_LIBS = @LIBSECCOMP_LIBS@ LIBLZMA_LIBS = @LIBLZMA_LIBS@ SQLITE3_LIBS = @SQLITE3_LIBS@ bash = @bash@ diff --git a/configure.ac b/configure.ac index 4e1806270..e6b11be2d 100644 --- a/configure.ac +++ b/configure.ac @@ -193,15 +193,6 @@ AC_SUBST(HAVE_SODIUM, [$have_sodium]) PKG_CHECK_MODULES([LIBLZMA], [liblzma], [CXXFLAGS="$LIBLZMA_CFLAGS $CXXFLAGS"]) -# Look for libseccomp, required for Linux sandboxing. -if test "$sys_name" = linux; then - PKG_CHECK_MODULES([LIBSECCOMP], [libseccomp], - [CXXFLAGS="$LIBSECCOMP_CFLAGS $CXXFLAGS"]) -# AC_CHECK_LIB([seccomp], [seccomp_init], [true], -# [AC_MSG_ERROR([Nix requires libseccomp for sandboxing. See https://github.com/seccomp/libseccomp.])]) -fi - - # Look for aws-cpp-sdk-s3. AC_LANG_PUSH(C++) AC_CHECK_HEADERS([aws/s3/S3Client.h], diff --git a/release.nix b/release.nix index 7c5e6125b..d825dd583 100644 --- a/release.nix +++ b/release.nix @@ -25,7 +25,7 @@ let buildInputs = [ curl bison flex perl libxml2 libxslt bzip2 xz - pkgconfig sqlite libsodium libseccomp boehmgc + pkgconfig sqlite libsodium boehmgc docbook5 docbook5_xsl autoconf-archive ] ++ lib.optional (!lib.inNixShell) git; @@ -74,7 +74,6 @@ let buildInputs = [ curl perl bzip2 xz openssl pkgconfig sqlite boehmgc ] ++ lib.optional stdenv.isLinux libsodium - ++ lib.optional stdenv.isLinux libseccomp ++ lib.optional stdenv.isLinux (aws-sdk-cpp.override { apis = ["s3"]; @@ -197,10 +196,6 @@ let nix = build.x86_64-linux; system = "x86_64-linux"; }); - tests.sandbox = (import ./tests/sandbox.nix rec { - nix = build.x86_64-linux; system = "x86_64-linux"; - }); - tests.binaryTarball = with import <nixpkgs> { system = "x86_64-linux"; }; vmTools.runInLinuxImage (runCommand "nix-binary-tarball-test" diff --git a/src/libstore/build.cc b/src/libstore/build.cc index f702433a0..c970fbdca 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -54,7 +54,6 @@ #include <sys/param.h> #include <sys/mount.h> #include <sys/syscall.h> -#include <seccomp.h> #define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old)) #endif @@ -815,6 +814,9 @@ private: result. */ ValidPathInfos prevInfos; + const uid_t sandboxUid = 1000; + const gid_t sandboxGid = 100; + public: DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode = bmNormal); @@ -1642,56 +1644,8 @@ void chmod_(const Path & path, mode_t mode) } -#if __linux__ - -#define FORCE_SUCCESS(syscall) \ - if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(0), SCMP_SYS(syscall), 0) != 0) { \ - seccomp_release(ctx); \ - throw SysError("unable to add seccomp rule for " #syscall); \ - } - -void setupSeccomp(void) { - scmp_filter_ctx ctx; - - if ((ctx = seccomp_init(SCMP_ACT_ALLOW)) == NULL) - throw SysError("unable to initialize seccomp mode 2"); - -#if defined(__x86_64__) - if (seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0) { - seccomp_release(ctx); - throw SysError("unable to add 32bit seccomp architecture"); - } -#endif - - FORCE_SUCCESS(chown32); - FORCE_SUCCESS(fchown32); - FORCE_SUCCESS(lchown32); - - FORCE_SUCCESS(chown); - FORCE_SUCCESS(fchown); - FORCE_SUCCESS(fchownat); - FORCE_SUCCESS(lchown); - - FORCE_SUCCESS(setxattr); - FORCE_SUCCESS(lsetxattr); - FORCE_SUCCESS(fsetxattr); - - if (seccomp_load(ctx) != 0) { - seccomp_release(ctx); - throw SysError("unable to load seccomp BPF program"); - } - - seccomp_release(ctx); -} - -#undef FORCE_SUCCESS - -#endif - - int childEntry(void * arg) { - setupSeccomp(); ((DerivationGoal *) arg)->runChild(); return 1; } @@ -2011,14 +1965,18 @@ void DerivationGoal::startBuilder() createDirs(chrootRootDir + "/etc"); writeFile(chrootRootDir + "/etc/passwd", - "root:x:0:0:Nix build user:/:/noshell\n" - "nobody:x:65534:65534:Nobody:/:/noshell\n"); + (format( + "root:x:0:0:Nix build user:/:/noshell\n" + "nixbld:x:%1%:%2%:Nix build user:/:/noshell\n" + "nobody:x:65534:65534:Nobody:/:/noshell\n") % sandboxUid % sandboxGid).str()); /* Declare the build user's group so that programs get a consistent view of the system (e.g., "id -gn"). */ writeFile(chrootRootDir + "/etc/group", - "root:x:0:\n" - "nobody:x:65534:\n"); + (format( + "root:x:0:\n" + "nixbld:!:%1%:\n" + "nogroup:x:65534:\n") % sandboxGid).str()); /* Create /etc/hosts with localhost entry. */ if (!fixedOutput) @@ -2202,7 +2160,12 @@ void DerivationGoal::startBuilder() Pid helper = startProcess([&]() { /* Drop additional groups here because we can't do it - after we've created the new user namespace. */ + after we've created the new user namespace. FIXME: + this means that if we're not root in the parent + namespace, we can't drop additional groups; they will + be mapped to nogroup in the child namespace. There does + not seem to be a workaround for this. (But who can tell + from reading user_namespaces(7)?)*/ if (getuid() == 0 && setgroups(0, 0) == -1) throw SysError("setgroups failed"); @@ -2235,19 +2198,19 @@ void DerivationGoal::startBuilder() if (!string2Int<pid_t>(readLine(builderOut.readSide.get()), tmp)) abort(); pid = tmp; - /* Set the UID/GID mapping of the builder's user - namespace such that root maps to the build user, or to the - calling user (if build users are disabled). */ - uid_t targetUid = buildUser.enabled() ? buildUser.getUID() : getuid(); - uid_t targetGid = buildUser.enabled() ? buildUser.getGID() : getgid(); + /* Set the UID/GID mapping of the builder's user namespace + such that the sandbox user maps to the build user, or to + the calling user (if build users are disabled). */ + uid_t hostUid = buildUser.enabled() ? buildUser.getUID() : getuid(); + uid_t hostGid = buildUser.enabled() ? buildUser.getGID() : getgid(); writeFile("/proc/" + std::to_string(pid) + "/uid_map", - (format("0 %d 1") % targetUid).str()); + (format("%d %d 1") % sandboxUid % hostUid).str()); writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny"); writeFile("/proc/" + std::to_string(pid) + "/gid_map", - (format("0 %d 1") % targetGid).str()); + (format("%d %d 1") % sandboxGid % hostGid).str()); /* Signal the builder that we've updated its user namespace. */ @@ -2457,11 +2420,12 @@ void DerivationGoal::runChild() if (rmdir("real-root") == -1) throw SysError("cannot remove real-root directory"); - /* Become root in the user namespace, which corresponds to - the build user or calling user in the parent namespace. */ - if (setgid(0) == -1) + /* Switch to the sandbox uid/gid in the user namespace, + which corresponds to the build user or calling user in + the parent namespace. */ + if (setgid(sandboxGid) == -1) throw SysError("setgid failed"); - if (setuid(0) == -1) + if (setuid(sandboxUid) == -1) throw SysError("setuid failed"); setUser = false; diff --git a/src/libstore/local.mk b/src/libstore/local.mk index a8222025c..9d5c04dca 100644 --- a/src/libstore/local.mk +++ b/src/libstore/local.mk @@ -18,10 +18,6 @@ ifeq ($(OS), SunOS) libstore_LDFLAGS += -lsocket endif -ifeq ($(OS), Linux) - libstore_LDFLAGS += -lseccomp -endif - libstore_CXXFLAGS = \ -DNIX_PREFIX=\"$(prefix)\" \ -DNIX_STORE_DIR=\"$(storedir)\" \ diff --git a/tests/sandbox.nix b/tests/sandbox.nix deleted file mode 100644 index dc72a5985..000000000 --- a/tests/sandbox.nix +++ /dev/null @@ -1,54 +0,0 @@ -# Test Nix builder sandbox. - -{ system, nix }: - -with import <nixpkgs/nixos/lib/testing.nix> { inherit system; }; - -let - mkUtils = pkgs: pkgs.buildEnv { - name = "sandbox-utils"; - paths = [ pkgs.coreutils pkgs.utillinux pkgs.bash ]; - pathsToLink = [ "/bin" "/sbin" ]; - }; - - utils32 = mkUtils pkgs.pkgsi686Linux; - utils64 = mkUtils pkgs; - - sandboxTestScript = pkgs.writeText "sandbox-testscript.sh" '' - [ $(id -u) -eq 0 ] - cp -p "$testfile" foo - chown 1024:1024 foo - touch "$out" - ''; - - testExpr = arch: pkgs.writeText "sandbox-test.nix" '' - let - utils = builtins.storePath - ${if arch == "i686-linux" then utils32 else utils64}; - in derivation { - name = "sandbox-test"; - system = "${arch}"; - builder = "''${utils}/bin/bash"; - args = ["-e" ${sandboxTestScript}]; - PATH = "''${utils}/bin"; - testfile = builtins.toFile "test" "i am a test file"; - } - ''; - -in makeTest { - name = "nix-sandbox"; - - machine = { pkgs, ... }: { - nix.package = nix; - nix.useSandbox = true; - nix.binaryCaches = []; - virtualisation.writableStore = true; - virtualisation.pathsInNixDB = [ utils32 utils64 ]; - }; - - testScript = '' - $machine->waitForUnit("multi-user.target"); - $machine->succeed("nix-build ${testExpr "x86_64-linux"}"); - $machine->succeed("nix-build ${testExpr "i686-linux"}"); - ''; -} |