From 09dc1d8ad625b9a1d5b89593b184d316837ba1cc Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Tue, 9 Apr 2019 18:19:04 +0200 Subject: build-support/build-sandbox: add support for mounting /nix Enables us to run nix *inside* of a sandbox. We have to mount the whole store, because otherwise realized store paths built inside of the sandbox are not accessible. --- pkgs/build-support/build-sandbox/default.nix | 42 +++++++++++++++++++-------- pkgs/build-support/build-sandbox/src/Makefile | 17 +++++++---- pkgs/build-support/build-sandbox/src/setup.c | 13 ++++++++- 3 files changed, 53 insertions(+), 19 deletions(-) (limited to 'pkgs/build-support') diff --git a/pkgs/build-support/build-sandbox/default.nix b/pkgs/build-support/build-sandbox/default.nix index 66797268..4e5cffe9 100644 --- a/pkgs/build-support/build-sandbox/default.nix +++ b/pkgs/build-support/build-sandbox/default.nix @@ -11,6 +11,10 @@ let pathsRuntimeVars = paths.runtimeVars or []; # Mount a dash shell in /bin/sh inside the chroot. allowBinSh = attrs.allowBinSh or false; + # Enable nix builds from within the sandbox. + # Has to write the full nix store to make the outputs accessible. + # TODO: get rid of nix & pkg-config if this is enabled (in the Makefile) + fullNixStore = attrs.fullNixStore or false; # Create code snippets for params.c to add extra_mount() calls. mkExtraMountParams = isRequired: lib.concatMapStringsSep "\n" (extra: let @@ -26,11 +30,13 @@ in stdenv.mkDerivation ({ inherit drv; + # writes files "sandbox-*" to the builder (see nix manual) exportReferencesGraph = [ "sandbox-closure" drv ] ++ lib.optionals allowBinSh [ "sandbox-binsh" dash ]; configurePhase = '' + # Reads the dependency closures and does … something? TODO: explain runtimeDeps="$(sed -ne ' p; n; n @@ -52,25 +58,36 @@ in stdenv.mkDerivation ({ echo '#include "setup.h"' > params.c echo 'bool setup_app_paths(void) {' >> params.c - for dep in $runtimeDeps; do - echo 'if (!bind_mount("'"$dep"'", true, true, true)) return false;' \ + ${if fullNixStore then '' + # /nix/var needs to be writable for nix to work inside the sandbox + echo 'if (!bind_mount("/nix/var", false, true, true)) return false;' \ + >> params.c + echo 'if (!bind_mount("/nix/store", true, true, true)) return false;' \ >> params.c - done + + '' else '' + for dep in $runtimeDeps; do + echo 'if (!bind_mount("'"$dep"'", true, true, true)) return false;' \ + >> params.c + done + ''} ${mkExtraMountParams true pathsRequired} ${mkExtraMountParams false pathsWanted} echo 'return true; }' >> params.c - echo 'bool mount_runtime_path_vars(struct query_state *qs) {' >> params.c + ${lib.optionalString (!fullNixStore) '' + echo 'bool mount_runtime_path_vars(struct query_state *qs) {' >> params.c - ${lib.concatMapStringsSep "\n" (pathvar: let - escaped = lib.escapeShellArg (lib.escape ["\\" "\""] pathvar); - fun = "mount_from_path_var"; - result = "echo 'if (!${fun}(qs, \"'${escaped}'\")) return false;'"; - in "${result} >> params.c") pathsRuntimeVars} + ${lib.concatMapStringsSep "\n" (pathvar: let + escaped = lib.escapeShellArg (lib.escape ["\\" "\""] pathvar); + fun = "mount_from_path_var"; + result = "echo 'if (!${fun}(qs, \"'${escaped}'\")) return false;'"; + in "${result} >> params.c") pathsRuntimeVars} - echo 'return true; }' >> params.c + echo 'return true; }' >> params.c + ''} ''; postInstall = '' @@ -82,8 +99,9 @@ in stdenv.mkDerivation ({ ''; nativeBuildInputs = [ pkgconfig ]; - buildInputs = [ nix boost ]; + buildInputs = [ boost nix ]; makeFlags = [ "BINDIR=${drv}/bin" ] - ++ lib.optional allowBinSh "BINSH_EXECUTABLE=${dash}/bin/dash"; + ++ lib.optional allowBinSh "BINSH_EXECUTABLE=${dash}/bin/dash" + ++ lib.optional fullNixStore "FULL_NIX_STORE=1"; } // removeAttrs attrs [ "paths" "allowBinSh" ]) diff --git a/pkgs/build-support/build-sandbox/src/Makefile b/pkgs/build-support/build-sandbox/src/Makefile index e18ec9d4..8e1218f6 100644 --- a/pkgs/build-support/build-sandbox/src/Makefile +++ b/pkgs/build-support/build-sandbox/src/Makefile @@ -1,19 +1,24 @@ BINARIES = $(wildcard $(BINDIR)/*) WRAPPERS = $(subst $(BINDIR),$(out)/bin,$(BINARIES)) +OBJECTS = path-cache.o params.o setup.o +CFLAGS = -g -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\" +CXXFLAGS = -g -Wall -std=c++14 `pkg-config --cflags nix-main` +LDFLAGS = -Wl,--copy-dt-needed-entries `pkg-config --libs nix-main` + +ifdef FULL_NIX_STORE +CFLAGS += -DFULL_NIX_STORE +else +OBJECTS += nix-query.o NIX_VERSION = `pkg-config --modversion nix-main | \ sed -e 's/^\([0-9]\+\)\.\([0-9][0-9]\).*/\1\2/' \ -e 's/^\([0-9]\+\)\.\([0-9]\).*/\10\2/'` +CXXFLAGS += -DNIX_VERSION=$(NIX_VERSION) +endif -OBJECTS = nix-query.o path-cache.o params.o setup.o - -CFLAGS = -g -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\" ifdef BINSH_EXECUTABLE CFLAGS += -DBINSH_EXECUTABLE=\"$(BINSH_EXECUTABLE)\" endif -CXXFLAGS = -g -Wall -std=c++14 `pkg-config --cflags nix-main` -CXXFLAGS += -DNIX_VERSION=$(NIX_VERSION) -LDFLAGS = -Wl,--copy-dt-needed-entries `pkg-config --libs nix-main` all: $(OBJECTS) diff --git a/pkgs/build-support/build-sandbox/src/setup.c b/pkgs/build-support/build-sandbox/src/setup.c index 8a5d29b5..8af42a06 100644 --- a/pkgs/build-support/build-sandbox/src/setup.c +++ b/pkgs/build-support/build-sandbox/src/setup.c @@ -18,8 +18,10 @@ #include #include "params.h" -#include "nix-query.h" #include "path-cache.h" +#ifndef FULL_NIX_STORE +#include "nix-query.h" +#endif static path_cache cached_paths = NULL; @@ -604,6 +606,7 @@ static bool setup_binsh(const char *executable) } #endif +#ifndef FULL_NIX_STORE static bool is_dir(const char *path) { struct stat sb; @@ -663,6 +666,9 @@ bool mount_from_path_var(struct query_state *qs, const char *name) return true; } +/* `/etc/static` is a special symlink on NixOS, pointing to a storepath + of configs that have to be available at runtime for some programs + to function. So we need to mount the closure of that storepath. */ static bool setup_static_etc(struct query_state *qs) { char dest[PATH_MAX]; @@ -680,6 +686,7 @@ static bool setup_static_etc(struct query_state *qs) return mount_requisites(qs, dest); } +/* Bind-mount all necessary nix store paths. */ static bool setup_runtime_paths(void) { struct query_state *qs; @@ -702,6 +709,7 @@ static bool setup_runtime_paths(void) free_query(qs); return true; } +#endif static bool setup_runtime_debug(void) { @@ -782,8 +790,11 @@ static bool setup_chroot(void) if (!bind_mount("/tmp", false, true, false)) return false; + // We don’t need to query the nix store if we mount the full store +#ifndef FULL_NIX_STORE if (!setup_runtime_paths()) return false; +#endif if (!setup_app_paths()) return false; -- cgit 1.4.1