From 96867dea2fcaefcbd8a2fa82fdd131bac37f0d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 23 Oct 2024 19:16:55 +0200 Subject: [PATCH] nix: fix macOS sandbox escape via builtin builders fixes https://github.com/NixOS/nix/security/advisories/GHSA-wf4c-57rh-9pjg (cherry picked from commit 2f6dc5c82c45d7a84049858078b93a591c7af33b) --- pkgs/tools/package-management/nix/common.nix | 4 + pkgs/tools/package-management/nix/default.nix | 51 +++ ...vation-builders-inside-the-sandbox-o.patch | 315 +++++++++++++++++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0003-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ ...vation-builders-inside-the-sandbox-o.patch | 312 +++++++++++++++++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0003-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ ...vation-builders-inside-the-sandbox-o.patch | 320 +++++++++++++++++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0003-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ ...vation-builders-inside-the-sandbox-o.patch | 320 +++++++++++++++++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0003-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ ...vation-builders-inside-the-sandbox-o.patch | 327 ++++++++++++++++++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0003-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ ...vation-builders-inside-the-sandbox-o.patch | 323 +++++++++++++++++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0003-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ ...vation-builders-inside-the-sandbox-o.patch | 323 +++++++++++++++++ ...ckaging-Add-darwin-lsandbox-in-meson.patch | 53 +++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0004-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ .../git/0001-Fix-meson-build-on-darwin.patch | 28 ++ ...vation-builders-inside-the-sandbox-o.patch | 323 +++++++++++++++++ ...ckaging-Add-darwin-lsandbox-in-meson.patch | 53 +++ ...-goal-Print-sandbox-error-detail-on-.patch | 34 ++ .../0005-local-derivation-goal-Refactor.patch | 41 +++ ...-goal-Move-builder-preparation-to-no.patch | 75 ++++ 37 files changed, 3952 insertions(+) create mode 100644 pkgs/tools/package-management/nix/patches/2_18/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_18/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_18/0003-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_18/0004-local-derivation-goal-Move-builder-preparation-to-no.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_19/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_19/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_19/0003-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_19/0004-local-derivation-goal-Move-builder-preparation-to-no.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_20/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_20/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_20/0003-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_20/0004-local-derivation-goal-Move-builder-preparation-to-no.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_21/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_21/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_21/0003-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_21/0004-local-derivation-goal-Move-builder-preparation-to-no.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_22/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_22/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_22/0003-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_22/0004-local-derivation-goal-Move-builder-preparation-to-no.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_23/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_23/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_23/0003-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_23/0004-local-derivation-goal-Move-builder-preparation-to-no.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_24/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_24/0002-packaging-Add-darwin-lsandbox-in-meson.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_24/0003-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_24/0004-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/2_24/0005-local-derivation-goal-Move-builder-preparation-to-no.patch create mode 100644 pkgs/tools/package-management/nix/patches/git/0001-Fix-meson-build-on-darwin.patch create mode 100644 pkgs/tools/package-management/nix/patches/git/0002-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch create mode 100644 pkgs/tools/package-management/nix/patches/git/0003-packaging-Add-darwin-lsandbox-in-meson.patch create mode 100644 pkgs/tools/package-management/nix/patches/git/0004-local-derivation-goal-Print-sandbox-error-detail-on-.patch create mode 100644 pkgs/tools/package-management/nix/patches/git/0005-local-derivation-goal-Refactor.patch create mode 100644 pkgs/tools/package-management/nix/patches/git/0006-local-derivation-goal-Move-builder-preparation-to-no.patch diff --git a/pkgs/tools/package-management/nix/common.nix b/pkgs/tools/package-management/nix/common.nix index a6b890fcb90d8..198034dc9a63a 100644 --- a/pkgs/tools/package-management/nix/common.nix +++ b/pkgs/tools/package-management/nix/common.nix @@ -16,6 +16,7 @@ let atLeast210 = lib.versionAtLeast version "2.10pre"; atLeast213 = lib.versionAtLeast version "2.13pre"; atLeast214 = lib.versionAtLeast version "2.14pre"; + atLeast218 = lib.versionAtLeast version "2.18pre"; atLeast219 = lib.versionAtLeast version "2.19pre"; atLeast220 = lib.versionAtLeast version "2.20pre"; atLeast221 = lib.versionAtLeast version "2.21pre"; @@ -42,6 +43,7 @@ in , callPackage , coreutils , curl +, darwin , docbook_xsl_ns , docbook5 , editline @@ -150,6 +152,8 @@ self = stdenv.mkDerivation { libseccomp ] ++ lib.optionals withAWS [ aws-sdk-cpp + ] ++ lib.optional (atLeast218 && stdenv.hostPlatform.isDarwin) [ + darwin.apple_sdk.libs.sandbox ]; installCheckInputs = lib.optionals atLeast221 [ diff --git a/pkgs/tools/package-management/nix/default.nix b/pkgs/tools/package-management/nix/default.nix index 50787eb5a2510..f24f3bb24d558 100644 --- a/pkgs/tools/package-management/nix/default.nix +++ b/pkgs/tools/package-management/nix/default.nix @@ -176,42 +176,85 @@ in lib.makeExtensible (self: ({ version = "2.18.8"; hash = "sha256-0rHRifdjzzxMh/im8pRx6XoY62irDTDUes+Pn0CR65I="; self_attribute_name = "nix_2_18"; + patches = [ + ./patches/2_18/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/2_18/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/2_18/0003-local-derivation-goal-Refactor.patch + ./patches/2_18/0004-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; }; nix_2_19 = common { version = "2.19.6"; hash = "sha256-XT5xiwOLgXf+TdyOjbJVOl992wu9mBO25WXHoyli/Tk="; self_attribute_name = "nix_2_19"; + patches = [ + ./patches/2_19/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/2_19/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/2_19/0003-local-derivation-goal-Refactor.patch + ./patches/2_19/0004-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; }; nix_2_20 = common { version = "2.20.8"; hash = "sha256-M2tkMtjKi8LDdNLsKi3IvD8oY/i3rtarjMpvhybS3WY="; self_attribute_name = "nix_2_20"; + patches = [ + ./patches/2_20/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/2_20/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/2_20/0003-local-derivation-goal-Refactor.patch + ./patches/2_20/0004-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; }; nix_2_21 = common { version = "2.21.4"; hash = "sha256-c6nVZ0pSrfhFX3eVKqayS+ioqyAGp3zG9ZPO5rkXFRQ="; self_attribute_name = "nix_2_21"; + patches = [ + ./patches/2_21/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/2_21/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/2_21/0003-local-derivation-goal-Refactor.patch + ./patches/2_21/0004-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; }; nix_2_22 = common { version = "2.22.3"; hash = "sha256-l04csH5rTWsK7eXPWVxJBUVRPMZXllFoSkYFTq/i8WU="; self_attribute_name = "nix_2_22"; + patches = [ + ./patches/2_22/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/2_22/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/2_22/0003-local-derivation-goal-Refactor.patch + ./patches/2_22/0004-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; }; nix_2_23 = common { version = "2.23.3"; hash = "sha256-lAoLGVIhRFrfgv7wcyduEkyc83QKrtsfsq4of+WrBeg="; self_attribute_name = "nix_2_23"; + patches = [ + ./patches/2_23/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/2_23/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/2_23/0003-local-derivation-goal-Refactor.patch + ./patches/2_23/0004-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; }; nix_2_24 = (common { version = "2.24.8"; hash = "sha256-YPJA0stZucs13Y2DQr3JIL6JfakP//LDbYXNhic/rKk="; self_attribute_name = "nix_2_24"; + patches = [ + ./patches/2_24/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/2_24/0002-packaging-Add-darwin-lsandbox-in-meson.patch + ./patches/2_24/0003-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/2_24/0004-local-derivation-goal-Refactor.patch + ./patches/2_24/0005-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; }).override (lib.optionalAttrs (stdenv.isDarwin && stdenv.isx86_64) { # Fix the following error with the default x86_64-darwin SDK: # @@ -232,6 +275,14 @@ in lib.makeExtensible (self: ({ rev = "ca3fc1693b309ab6b8b0c09408a08d0055bf0363"; hash = "sha256-Hp7dkx7zfB9a4l5QusXUob0b1T2qdZ23LFo5dcp3xrU="; }; + patches = [ + ./patches/git/0001-Fix-meson-build-on-darwin.patch + ./patches/git/0002-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch + ./patches/git/0003-packaging-Add-darwin-lsandbox-in-meson.patch + ./patches/git/0004-local-derivation-goal-Print-sandbox-error-detail-on-.patch + ./patches/git/0005-local-derivation-goal-Refactor.patch + ./patches/git/0006-local-derivation-goal-Move-builder-preparation-to-no.patch + ]; self_attribute_name = "git"; }).override (lib.optionalAttrs (stdenv.isDarwin && stdenv.isx86_64) { # Fix the following error with the default x86_64-darwin SDK: diff --git a/pkgs/tools/package-management/nix/patches/2_18/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/2_18/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..c13844f8bdd79 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_18/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,315 @@ +From 3c4bc6929eb13cf648c54931a28797bb1c289052 Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 1/4] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + flake.nix | 1 + + src/libstore/build/local-derivation-goal.cc | 221 ++++++++++---------- + 3 files changed, 114 insertions(+), 114 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 4e50d0913..44852ad79 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -58,13 +58,17 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + AC_STRUCT_DIRENT_D_TYPE + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/flake.nix b/flake.nix +index 6c9bef4d8..66ac1bfd8 100644 +--- a/flake.nix ++++ b/flake.nix +@@ -173,6 +173,7 @@ + boost + lowdown-nix + ] ++ ++ lib.optionals stdenv.isDarwin [darwin.apple_sdk.libs.sandbox] + ++ lib.optionals stdenv.isLinux [(libseccomp.overrideAttrs (_: rec { + version = "2.5.5"; + src = fetchurl { +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index 4d690beaf..fb83cfdc7 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -53,6 +53,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2034,141 +2038,132 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : dirsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; + +- /* And we want the store in there regardless of how empty dirsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ if (useChroot) { ++ ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : dirsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- dirsInChroot[p] = p; +- } +- +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* And we want the store in there regardless of how empty dirsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- sandboxProfile += +- #include "sandbox-defaults.sb" +- ; ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ dirsInChroot[p] = p; ++ } + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : dirsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- struct stat st; +- if (lstat(path.c_str(), &st)) { +- if (i.second.optional && errno == ENOENT) +- continue; +- throw SysError("getting attributes of path '%s", path); +- } +- if (S_ISDIR(st.st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; + +- sandboxProfile += additionalSandboxProfile; +- } else ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-minimal.sb" ++ #include "sandbox-network.sb" + ; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ sandboxProfile += ")\n"; + +- writeFile(sandboxFile, sandboxProfile); ++ /* Our inputs (transitive dependencies and any impurities computed above) + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : dirsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ +- Path globalTmpDir = canonPath(defaultTempDir(), true); ++ std::string path = i.first; ++ struct stat st; ++ if (lstat(path.c_str(), &st)) { ++ if (i.second.optional && errno == ENOENT) ++ continue; ++ throw SysError("getting attributes of path '%s", path); ++ } ++ if (S_ISDIR(st.st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- /* They don't like trailing slashes on subpath directives */ +- while (!globalTmpDir.empty() && globalTmpDir.back() == '/') +- globalTmpDir.pop_back(); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; ++ ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); ++ ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ ++ Path globalTmpDir = canonPath(defaultTempDir(), true); ++ ++ /* They don't like trailing slashes on subpath directives */ ++ while (!globalTmpDir.empty() && globalTmpDir.back() == '/') ++ globalTmpDir.pop_back(); ++ ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_18/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/2_18/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..a3bc4f05cdaff --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_18/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From 4ac099d6ab4b6851aeb8b7a1e37f5794716d5138 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 2/4] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index fb83cfdc7..d41d1c1e5 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2154,8 +2154,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_18/0003-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/2_18/0003-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..81997405a5f71 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_18/0003-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From 6fe3a5e26def808b99856099d74aa3017ecf6d9d Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 3/4] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index d41d1c1e5..faecc403b 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2160,15 +2160,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_18/0004-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/2_18/0004-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..4a17ccedbdbd2 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_18/0004-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From d219faa93badcfc8134c81ba0d2b821775eb947c Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 4/4] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 25 +++++++++------------ + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index faecc403b..23d5d5e3f 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2033,11 +2033,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2162,14 +2157,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2199,6 +2186,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2220,9 +2215,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_19/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/2_19/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..dfe091b48c7dd --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_19/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,312 @@ +From 172734f47a8062285cec0055133efcc45df03e54 Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 1/4] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + flake.nix | 1 + + src/libstore/build/local-derivation-goal.cc | 217 ++++++++++---------- + 3 files changed, 112 insertions(+), 112 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 281ba2c32..6d73804e2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -58,13 +58,17 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + AC_STRUCT_DIRENT_D_TYPE + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/flake.nix b/flake.nix +index 6deb09f22..98f9cc25f 100644 +--- a/flake.nix ++++ b/flake.nix +@@ -202,6 +202,7 @@ + libsodium + ] + ++ lib.optionals stdenv.isLinux [libseccomp] ++ ++ lib.optionals stdenv.isDarwin [darwin.apple_sdk.libs.sandbox] + ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid; + + checkDeps = [ +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index b6c7666e5..effd9c613 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -55,6 +55,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2031,140 +2035,131 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : pathsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; + +- /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ if (useChroot) { ++ ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : pathsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- pathsInChroot[p] = p; +- } ++ /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ pathsInChroot[p] = p; ++ } ++ ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; ++ ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-defaults.sb" ++ #include "sandbox-network.sb" + ; + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : pathsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- struct stat st; +- if (lstat(path.c_str(), &st)) { +- if (i.second.optional && errno == ENOENT) +- continue; +- throw SysError("getting attributes of path '%s", path); +- } +- if (S_ISDIR(st.st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ")\n"; + +- sandboxProfile += additionalSandboxProfile; +- } else +- sandboxProfile += +- #include "sandbox-minimal.sb" +- ; ++ /* Our inputs (transitive dependencies and any impurities computed above) ++ ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : pathsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); ++ ++ std::string path = i.first; ++ struct stat st; ++ if (lstat(path.c_str(), &st)) { ++ if (i.second.optional && errno == ENOENT) ++ continue; ++ throw SysError("getting attributes of path '%s", path); ++ } ++ if (S_ISDIR(st.st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; + +- writeFile(sandboxFile, sandboxProfile); ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ +- Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true); ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ ++ Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true); + +- /* They don't like trailing slashes on subpath directives */ +- if (globalTmpDir.back() == '/') globalTmpDir.pop_back(); ++ /* They don't like trailing slashes on subpath directives */ ++ if (globalTmpDir.back() == '/') globalTmpDir.pop_back(); + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_19/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/2_19/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..8378f739dd7ec --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_19/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From 4a5018019e969537fdba36314fe5c19fe91828af Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 2/4] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index effd9c613..a67347b59 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2150,8 +2150,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_19/0003-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/2_19/0003-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..f98d7069b5548 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_19/0003-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From f9e5b3b52323fdcac4e21bfec4d03bd66ea6a503 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 3/4] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index a67347b59..eeb2635ee 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2156,15 +2156,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_19/0004-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/2_19/0004-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..523e0edea3d98 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_19/0004-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From 126a1fd3385175ac94ae4000a9798e0cafb3c168 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 4/4] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 25 +++++++++------------ + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index eeb2635ee..e29330f0e 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2030,11 +2030,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2158,14 +2153,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2195,6 +2182,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2216,9 +2211,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_20/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/2_20/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..6c5d8b7859906 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_20/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,320 @@ +From aa54b01af503644a393e4e4055c4ce2a23ce9139 Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 1/4] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + package.nix | 2 + + src/libstore/build/local-derivation-goal.cc | 217 ++++++++++---------- + 3 files changed, 113 insertions(+), 112 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 8c29c1e62..8c524fd93 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -58,13 +58,17 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + AC_STRUCT_DIRENT_D_TYPE + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/package.nix b/package.nix +index d1d14d10e..40283ffcf 100644 +--- a/package.nix ++++ b/package.nix +@@ -24,6 +24,7 @@ + , libgit2 + , libseccomp + , libsodium ++, darwin + , lowdown + , mdbook + , mdbook-linkcheck +@@ -233,6 +234,7 @@ in { + gtest + rapidcheck + ] ++ lib.optional stdenv.isLinux libseccomp ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox + ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid + # There have been issues building these dependencies + ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin)) +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index b8228bc11..9ab676429 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -57,6 +57,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2023,140 +2027,131 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : pathsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; + +- /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ if (useChroot) { ++ ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : pathsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- pathsInChroot[p] = p; +- } ++ /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ pathsInChroot[p] = p; ++ } ++ ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; ++ ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-defaults.sb" ++ #include "sandbox-network.sb" + ; + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : pathsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- struct stat st; +- if (lstat(path.c_str(), &st)) { +- if (i.second.optional && errno == ENOENT) +- continue; +- throw SysError("getting attributes of path '%s", path); +- } +- if (S_ISDIR(st.st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ")\n"; + +- sandboxProfile += additionalSandboxProfile; +- } else +- sandboxProfile += +- #include "sandbox-minimal.sb" +- ; ++ /* Our inputs (transitive dependencies and any impurities computed above) ++ ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : pathsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); ++ ++ std::string path = i.first; ++ struct stat st; ++ if (lstat(path.c_str(), &st)) { ++ if (i.second.optional && errno == ENOENT) ++ continue; ++ throw SysError("getting attributes of path '%s", path); ++ } ++ if (S_ISDIR(st.st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; + +- writeFile(sandboxFile, sandboxProfile); ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ +- Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true); ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ ++ Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true); + +- /* They don't like trailing slashes on subpath directives */ +- if (globalTmpDir.back() == '/') globalTmpDir.pop_back(); ++ /* They don't like trailing slashes on subpath directives */ ++ if (globalTmpDir.back() == '/') globalTmpDir.pop_back(); + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_20/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/2_20/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..d644be6703e72 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_20/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From b78e489f79165457b59faa2270fd89769d0fc17d Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 2/4] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index 9ab676429..8476e038e 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2142,8 +2142,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_20/0003-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/2_20/0003-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..05e8c5843acea --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_20/0003-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From db6bcf3f7714929d5a21b655c5f8ccd2ddbdf7f2 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 3/4] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index 8476e038e..12b67df69 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2148,15 +2148,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_20/0004-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/2_20/0004-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..852940d3b711b --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_20/0004-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From 55be7deee1471e77e3ad408c5e23842df0d5bc28 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 4/4] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 25 +++++++++------------ + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index 12b67df69..ada86dbb8 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2022,11 +2022,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2150,14 +2145,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2187,6 +2174,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2208,9 +2203,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_21/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/2_21/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..d35d20896e6b5 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_21/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,320 @@ +From ae8a38d29cc0fbd6394acd72fdaaa62b3798f698 Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 1/4] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + package.nix | 2 + + src/libstore/build/local-derivation-goal.cc | 217 ++++++++++---------- + 3 files changed, 113 insertions(+), 112 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 676b145a5..f6fa35c81 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -62,13 +62,17 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + AC_STRUCT_DIRENT_D_TYPE + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/package.nix b/package.nix +index 7d9a39771..de2e1aff1 100644 +--- a/package.nix ++++ b/package.nix +@@ -25,6 +25,7 @@ + , libseccomp + , libsodium + , man ++, darwin + , lowdown + , mdbook + , mdbook-linkcheck +@@ -239,6 +240,7 @@ in { + gtest + rapidcheck + ] ++ lib.optional stdenv.isLinux libseccomp ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox + ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid + # There have been issues building these dependencies + ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin)) +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index 710304b67..c73b30b80 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -58,6 +58,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2018,140 +2022,131 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : pathsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; + +- /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ if (useChroot) { ++ ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : pathsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- pathsInChroot[p] = p; +- } ++ /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ pathsInChroot[p] = p; ++ } ++ ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; ++ ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-defaults.sb" ++ #include "sandbox-network.sb" + ; + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : pathsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- struct stat st; +- if (lstat(path.c_str(), &st)) { +- if (i.second.optional && errno == ENOENT) +- continue; +- throw SysError("getting attributes of path '%s", path); +- } +- if (S_ISDIR(st.st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ")\n"; + +- sandboxProfile += additionalSandboxProfile; +- } else +- sandboxProfile += +- #include "sandbox-minimal.sb" +- ; ++ /* Our inputs (transitive dependencies and any impurities computed above) ++ ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : pathsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); ++ ++ std::string path = i.first; ++ struct stat st; ++ if (lstat(path.c_str(), &st)) { ++ if (i.second.optional && errno == ENOENT) ++ continue; ++ throw SysError("getting attributes of path '%s", path); ++ } ++ if (S_ISDIR(st.st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; + +- writeFile(sandboxFile, sandboxProfile); ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ +- Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true); ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */ ++ Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true); + +- /* They don't like trailing slashes on subpath directives */ +- if (globalTmpDir.back() == '/') globalTmpDir.pop_back(); ++ /* They don't like trailing slashes on subpath directives */ ++ if (globalTmpDir.back() == '/') globalTmpDir.pop_back(); + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_21/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/2_21/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..053d3eb672d99 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_21/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From b429e96583e2d005c77df8c82261022397f20648 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 2/4] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index c73b30b80..e6f4c397d 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2137,8 +2137,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_21/0003-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/2_21/0003-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..97809a556b57e --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_21/0003-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From 74b93c1edba00c2601e20b8acdcc78e29bd3f092 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 3/4] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index e6f4c397d..e81818fa8 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2143,15 +2143,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_21/0004-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/2_21/0004-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..b2f3b2b7815cf --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_21/0004-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From c8de35f74cbce58651c3b64ba66061040f546b9f Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 4/4] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + src/libstore/build/local-derivation-goal.cc | 25 +++++++++------------ + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc +index e81818fa8..078f1a5be 100644 +--- a/src/libstore/build/local-derivation-goal.cc ++++ b/src/libstore/build/local-derivation-goal.cc +@@ -2017,11 +2017,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2145,14 +2140,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2183,6 +2170,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2204,9 +2199,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_22/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/2_22/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..72470dec5fd26 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_22/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,327 @@ +From 8217054e3554ffd376f42fb0a65087a7af2ddfab Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 1/4] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + package.nix | 5 +- + .../unix/build/local-derivation-goal.cc | 223 +++++++++--------- + 3 files changed, 118 insertions(+), 116 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 8f60bf4be..5e67e04be 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -62,13 +62,17 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + AC_STRUCT_DIRENT_D_TYPE + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/package.nix b/package.nix +index 59265f522..28be97400 100644 +--- a/package.nix ++++ b/package.nix +@@ -27,6 +27,7 @@ + , libseccomp + , libsodium + , man ++, darwin + , lowdown + , mdbook + , mdbook-linkcheck +@@ -249,7 +250,9 @@ in { + ] ++ lib.optionals buildUnitTests [ + gtest + rapidcheck +- ] ++ lib.optional stdenv.isLinux (libseccomp.overrideAttrs (_: rec { ++ ] ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox ++ ++ lib.optional stdenv.isLinux (libseccomp.overrideAttrs (_: rec { + version = "2.5.5"; + src = fetchurl { + url = "https://github.com/seccomp/libseccomp/releases/download/v${version}/libseccomp-${version}.tar.gz"; +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index b8ccdf834..449d4b07c 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -58,6 +58,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2026,141 +2030,132 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : pathsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; ++ ++ if (useChroot) { + +- /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : pathsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- pathsInChroot[p] = p; +- } +- +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- sandboxProfile += +- #include "sandbox-defaults.sb" +- ; ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ pathsInChroot[p] = p; ++ } + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : pathsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- auto optSt = maybeLstat(path.c_str()); +- if (!optSt) { +- if (i.second.optional) +- continue; +- throw SysError("getting attributes of required path '%s", path); +- } +- if (S_ISDIR(optSt->st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; + +- sandboxProfile += additionalSandboxProfile; +- } else ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-minimal.sb" ++ #include "sandbox-network.sb" + ; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); +- +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- writeFile(sandboxFile, sandboxProfile); ++ sandboxProfile += ")\n"; + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ /* Our inputs (transitive dependencies and any impurities computed above) + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ +- Path globalTmpDir = canonPath(defaultTempDir(), true); ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : pathsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); ++ ++ std::string path = i.first; ++ auto optSt = maybeLstat(path.c_str()); ++ if (!optSt) { ++ if (i.second.optional) ++ continue; ++ throw SysError("getting attributes of required path '%s", path); ++ } ++ if (S_ISDIR(optSt->st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- /* They don't like trailing slashes on subpath directives */ +- while (!globalTmpDir.empty() && globalTmpDir.back() == '/') +- globalTmpDir.pop_back(); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; ++ ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); ++ ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ ++ Path globalTmpDir = canonPath(defaultTempDir(), true); ++ ++ /* They don't like trailing slashes on subpath directives */ ++ while (!globalTmpDir.empty() && globalTmpDir.back() == '/') ++ globalTmpDir.pop_back(); ++ ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_22/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/2_22/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..6ac281e6316c5 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_22/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From f0677f190d0bd042c3a864508a5307b19a2c2d26 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 2/4] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 449d4b07c..b74bd2e64 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2146,8 +2146,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_22/0003-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/2_22/0003-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..dfb5add1978db --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_22/0003-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From 1b39753f4d63465c709d18482945ce680b6f3f1e Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 3/4] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index b74bd2e64..9b8b3c51b 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2152,15 +2152,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_22/0004-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/2_22/0004-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..8e200685dc736 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_22/0004-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From 9e198a75f76ac08f835975d4b2743e156616a219 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 4/4] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + .../unix/build/local-derivation-goal.cc | 25 ++++++++----------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 9b8b3c51b..08366712c 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2025,11 +2025,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2154,14 +2149,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2192,6 +2179,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2213,9 +2208,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_23/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/2_23/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..f309ff6818d4c --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_23/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,323 @@ +From 05994033d58e358ddafe51d1d04626eb76b8a192 Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 1/4] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + package.nix | 2 + + .../unix/build/local-derivation-goal.cc | 223 +++++++++--------- + 3 files changed, 116 insertions(+), 115 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 90a6d45d5..f98a0a5ea 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -62,12 +62,16 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/package.nix b/package.nix +index cf1654c6a..1dfe7ab31 100644 +--- a/package.nix ++++ b/package.nix +@@ -27,6 +27,7 @@ + , libseccomp + , libsodium + , man ++, darwin + , lowdown + , mdbook + , mdbook-linkcheck +@@ -250,6 +251,7 @@ in { + gtest + rapidcheck + ] ++ lib.optional stdenv.isLinux libseccomp ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox + ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid + # There have been issues building these dependencies + ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin)) +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index ae9c715d6..878644fa5 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -58,6 +58,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2017,141 +2021,132 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : pathsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; ++ ++ if (useChroot) { + +- /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : pathsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- pathsInChroot[p] = p; +- } +- +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- sandboxProfile += +- #include "sandbox-defaults.sb" +- ; ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ pathsInChroot[p] = p; ++ } + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : pathsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- auto optSt = maybeLstat(path.c_str()); +- if (!optSt) { +- if (i.second.optional) +- continue; +- throw SysError("getting attributes of required path '%s", path); +- } +- if (S_ISDIR(optSt->st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; + +- sandboxProfile += additionalSandboxProfile; +- } else ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-minimal.sb" ++ #include "sandbox-network.sb" + ; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); +- +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- writeFile(sandboxFile, sandboxProfile); ++ sandboxProfile += ")\n"; + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ /* Our inputs (transitive dependencies and any impurities computed above) + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ +- Path globalTmpDir = canonPath(defaultTempDir(), true); ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : pathsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); ++ ++ std::string path = i.first; ++ auto optSt = maybeLstat(path.c_str()); ++ if (!optSt) { ++ if (i.second.optional) ++ continue; ++ throw SysError("getting attributes of required path '%s", path); ++ } ++ if (S_ISDIR(optSt->st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- /* They don't like trailing slashes on subpath directives */ +- while (!globalTmpDir.empty() && globalTmpDir.back() == '/') +- globalTmpDir.pop_back(); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; ++ ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); ++ ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ ++ Path globalTmpDir = canonPath(defaultTempDir(), true); ++ ++ /* They don't like trailing slashes on subpath directives */ ++ while (!globalTmpDir.empty() && globalTmpDir.back() == '/') ++ globalTmpDir.pop_back(); ++ ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_23/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/2_23/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..e264b4f1b4dcf --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_23/0002-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From c43954ffac356b4168cbcfe2a67b4bad3f0dff5d Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 2/4] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 878644fa5..0df1f0683 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2137,8 +2137,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_23/0003-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/2_23/0003-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..27c632b041dda --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_23/0003-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From 53b4bdcb8b0f114bea978cffbea325fd73f779b5 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 3/4] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 0df1f0683..9e67283c9 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2143,15 +2143,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_23/0004-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/2_23/0004-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..6ef5c8e48c4c5 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_23/0004-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From 67b5c7004302cbd344f63ccd306673a9adec4520 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 4/4] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + .../unix/build/local-derivation-goal.cc | 25 ++++++++----------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 9e67283c9..1f4bafb56 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2016,11 +2016,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2145,14 +2140,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2183,6 +2170,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2204,9 +2199,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_24/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/2_24/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..9c3d5f987da2c --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_24/0001-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,323 @@ +From 170242cf0ca3e9fadbad2004126793634d56623e Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 1/5] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + package.nix | 2 + + .../unix/build/local-derivation-goal.cc | 223 +++++++++--------- + 3 files changed, 116 insertions(+), 115 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 5c22ed176..dff35981b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -62,12 +62,16 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/package.nix b/package.nix +index a7c8923e8..fcd1e1898 100644 +--- a/package.nix ++++ b/package.nix +@@ -23,6 +23,7 @@ + , libseccomp + , libsodium + , man ++, darwin + , lowdown + , mdbook + , mdbook-linkcheck +@@ -235,6 +236,7 @@ in { + gtest + rapidcheck + ] ++ lib.optional stdenv.isLinux libseccomp ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox + ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid + # There have been issues building these dependencies + ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin)) +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 54ca69580..7ce266122 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -58,6 +58,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2039,141 +2043,132 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : pathsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; ++ ++ if (useChroot) { + +- /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : pathsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- pathsInChroot[p] = p; +- } +- +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- sandboxProfile += +- #include "sandbox-defaults.sb" +- ; ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ pathsInChroot[p] = p; ++ } + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : pathsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- auto optSt = maybeLstat(path.c_str()); +- if (!optSt) { +- if (i.second.optional) +- continue; +- throw SysError("getting attributes of required path '%s", path); +- } +- if (S_ISDIR(optSt->st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; + +- sandboxProfile += additionalSandboxProfile; +- } else ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-minimal.sb" ++ #include "sandbox-network.sb" + ; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); +- +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- writeFile(sandboxFile, sandboxProfile); ++ sandboxProfile += ")\n"; + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ /* Our inputs (transitive dependencies and any impurities computed above) + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ +- Path globalTmpDir = canonPath(defaultTempDir(), true); ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : pathsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); ++ ++ std::string path = i.first; ++ auto optSt = maybeLstat(path.c_str()); ++ if (!optSt) { ++ if (i.second.optional) ++ continue; ++ throw SysError("getting attributes of required path '%s", path); ++ } ++ if (S_ISDIR(optSt->st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- /* They don't like trailing slashes on subpath directives */ +- while (!globalTmpDir.empty() && globalTmpDir.back() == '/') +- globalTmpDir.pop_back(); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; ++ ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); ++ ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ ++ Path globalTmpDir = canonPath(defaultTempDir(), true); ++ ++ /* They don't like trailing slashes on subpath directives */ ++ while (!globalTmpDir.empty() && globalTmpDir.back() == '/') ++ globalTmpDir.pop_back(); ++ ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_24/0002-packaging-Add-darwin-lsandbox-in-meson.patch b/pkgs/tools/package-management/nix/patches/2_24/0002-packaging-Add-darwin-lsandbox-in-meson.patch new file mode 100644 index 0000000000000..c709ea62354df --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_24/0002-packaging-Add-darwin-lsandbox-in-meson.patch @@ -0,0 +1,53 @@ +From f8a1a149c73113e01c44b73ce9e1005575d52a9a Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:23:17 +0200 +Subject: [PATCH 2/5] packaging: Add darwin -lsandbox in meson +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + src/libstore/meson.build | 5 +++++ + src/libstore/package.nix | 2 ++ + 2 files changed, 7 insertions(+) + +diff --git a/src/libstore/meson.build b/src/libstore/meson.build +index 50b15e15d..b23c85061 100644 +--- a/src/libstore/meson.build ++++ b/src/libstore/meson.build +@@ -68,6 +68,11 @@ has_acl_support = cxx.has_header('sys/xattr.h') \ + and cxx.has_function('lremovexattr') + configdata.set('HAVE_ACL_SUPPORT', has_acl_support.to_int()) + ++if host_machine.system() == 'darwin' ++ sandbox = cxx.find_library('sandbox') ++ deps_other += [sandbox] ++endif ++ + subdir('build-utils-meson/threads') + + boost = dependency( +diff --git a/src/libstore/package.nix b/src/libstore/package.nix +index 4582ba0d2..d98bac16d 100644 +--- a/src/libstore/package.nix ++++ b/src/libstore/package.nix +@@ -7,6 +7,7 @@ + , ninja + , pkg-config + , unixtools ++, darwin + + , nix-util + , boost +@@ -65,6 +66,7 @@ mkMesonDerivation (finalAttrs: { + sqlite + ] ++ lib.optional stdenv.hostPlatform.isLinux libseccomp + # There have been issues building these dependencies ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox + ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin)) + aws-sdk-cpp + ; +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_24/0003-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/2_24/0003-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..2c984b6343dba --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_24/0003-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From ae7a2ea74136363c2f6ac6e624ea95da7abfafcc Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 3/5] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 7ce266122..706771e8e 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2159,8 +2159,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_24/0004-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/2_24/0004-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..dbf54c5020c9a --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_24/0004-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From 047ee50db2f660eb3f50fab8f7543ce95e814b7c Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 4/5] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 706771e8e..d9738a1ea 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2165,15 +2165,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/2_24/0005-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/2_24/0005-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..c4fc9b2c2117b --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/2_24/0005-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From 50f83e4bbd9107576399f94449ac9cb4e80d575e Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 5/5] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + .../unix/build/local-derivation-goal.cc | 25 ++++++++----------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index d9738a1ea..2a09e3dd4 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2038,11 +2038,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2167,14 +2162,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2205,6 +2192,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2226,9 +2221,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/git/0001-Fix-meson-build-on-darwin.patch b/pkgs/tools/package-management/nix/patches/git/0001-Fix-meson-build-on-darwin.patch new file mode 100644 index 0000000000000..e03bed0145614 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/git/0001-Fix-meson-build-on-darwin.patch @@ -0,0 +1,28 @@ +From 766263d53ae69d70c5915426e6e8f58abd988226 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Tue, 22 Oct 2024 15:28:04 +0200 +Subject: [PATCH 1/6] Fix meson build on darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +std::stringbuf is defined in +Signed-off-by: Jörg Thalheim +--- + src/libutil/strings.cc | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/libutil/strings.cc b/src/libutil/strings.cc +index d1c9f700c..c221a43c6 100644 +--- a/src/libutil/strings.cc ++++ b/src/libutil/strings.cc +@@ -1,5 +1,6 @@ + #include + #include ++#include + + #include "strings-inline.hh" + #include "os-string.hh" +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/git/0002-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch b/pkgs/tools/package-management/nix/patches/git/0002-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch new file mode 100644 index 0000000000000..36218646f3b62 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/git/0002-fix-Run-all-derivation-builders-inside-the-sandbox-o.patch @@ -0,0 +1,323 @@ +From d2c880b03f58eb4fdd6d19eb3ffa4345a0477419 Mon Sep 17 00:00:00 2001 +From: Puck Meerburg +Date: Fri, 1 Mar 2024 11:42:24 -0500 +Subject: [PATCH 2/6] fix: Run all derivation builders inside the sandbox on + macOS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + configure.ac | 6 +- + package.nix | 2 + + .../unix/build/local-derivation-goal.cc | 223 +++++++++--------- + 3 files changed, 116 insertions(+), 115 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 198198dea..c7c9b3f4b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -62,12 +62,16 @@ AC_CHECK_TOOL([AR], [ar]) + AC_SYS_LARGEFILE + + +-# Solaris-specific stuff. ++# OS-specific stuff. + case "$host_os" in + solaris*) + # Solaris requires -lsocket -lnsl for network functions + LDFLAGS="-lsocket -lnsl $LDFLAGS" + ;; ++ darwin*) ++ # Need to link to libsandbox. ++ LDFLAGS="-lsandbox $LDFLAGS" ++ ;; + esac + + +diff --git a/package.nix b/package.nix +index 00621d475..77f1de58c 100644 +--- a/package.nix ++++ b/package.nix +@@ -23,6 +23,7 @@ + , libseccomp + , libsodium + , man ++, darwin + , lowdown + , mdbook + , mdbook-linkcheck +@@ -232,6 +233,7 @@ in { + gtest + rapidcheck + ] ++ lib.optional stdenv.isLinux libseccomp ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox + ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid + # There have been issues building these dependencies + ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin)) +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index b4685b3a7..067755c0d 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -58,6 +58,10 @@ + #if __APPLE__ + #include + #include ++#include ++ ++/* This definition is undocumented but depended upon by all major browsers. */ ++extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); + #endif + + #include +@@ -2088,141 +2092,132 @@ void LocalDerivationGoal::runChild() + + std::string builder = "invalid"; + +- if (drv->isBuiltin()) { +- ; +- } + #if __APPLE__ +- else { +- /* This has to appear before import statements. */ +- std::string sandboxProfile = "(version 1)\n"; +- +- if (useChroot) { +- +- /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ +- PathSet ancestry; +- +- /* We build the ancestry before adding all inputPaths to the store because we know they'll +- all have the same parents (the store), and there might be lots of inputs. This isn't +- particularly efficient... I doubt it'll be a bottleneck in practice */ +- for (auto & i : pathsInChroot) { +- Path cur = i.first; +- while (cur.compare("/") != 0) { +- cur = dirOf(cur); +- ancestry.insert(cur); +- } +- } ++ /* This has to appear before import statements. */ ++ std::string sandboxProfile = "(version 1)\n"; ++ ++ if (useChroot) { + +- /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost +- path component this time, since it's typically /nix/store and we care about that. */ +- Path cur = worker.store.storeDir; ++ /* Lots and lots and lots of file functions freak out if they can't stat their full ancestry */ ++ PathSet ancestry; ++ ++ /* We build the ancestry before adding all inputPaths to the store because we know they'll ++ all have the same parents (the store), and there might be lots of inputs. This isn't ++ particularly efficient... I doubt it'll be a bottleneck in practice */ ++ for (auto & i : pathsInChroot) { ++ Path cur = i.first; + while (cur.compare("/") != 0) { +- ancestry.insert(cur); + cur = dirOf(cur); ++ ancestry.insert(cur); + } ++ } + +- /* Add all our input paths to the chroot */ +- for (auto & i : inputPaths) { +- auto p = worker.store.printStorePath(i); +- pathsInChroot[p] = p; +- } +- +- /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ +- if (settings.darwinLogSandboxViolations) { +- sandboxProfile += "(deny default)\n"; +- } else { +- sandboxProfile += "(deny default (with no-log))\n"; +- } ++ /* And we want the store in there regardless of how empty pathsInChroot. We include the innermost ++ path component this time, since it's typically /nix/store and we care about that. */ ++ Path cur = worker.store.storeDir; ++ while (cur.compare("/") != 0) { ++ ancestry.insert(cur); ++ cur = dirOf(cur); ++ } + +- sandboxProfile += +- #include "sandbox-defaults.sb" +- ; ++ /* Add all our input paths to the chroot */ ++ for (auto & i : inputPaths) { ++ auto p = worker.store.printStorePath(i); ++ pathsInChroot[p] = p; ++ } + +- if (!derivationType->isSandboxed()) +- sandboxProfile += +- #include "sandbox-network.sb" +- ; +- +- /* Add the output paths we'll use at build-time to the chroot */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & [_, path] : scratchOutputs) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); +- +- sandboxProfile += ")\n"; +- +- /* Our inputs (transitive dependencies and any impurities computed above) +- +- without file-write* allowed, access() incorrectly returns EPERM +- */ +- sandboxProfile += "(allow file-read* file-write* process-exec\n"; +- for (auto & i : pathsInChroot) { +- if (i.first != i.second.source) +- throw Error( +- "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", +- i.first, i.second.source); +- +- std::string path = i.first; +- auto optSt = maybeLstat(path.c_str()); +- if (!optSt) { +- if (i.second.optional) +- continue; +- throw SysError("getting attributes of required path '%s", path); +- } +- if (S_ISDIR(optSt->st_mode)) +- sandboxProfile += fmt("\t(subpath \"%s\")\n", path); +- else +- sandboxProfile += fmt("\t(literal \"%s\")\n", path); +- } +- sandboxProfile += ")\n"; ++ /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ ++ if (settings.darwinLogSandboxViolations) { ++ sandboxProfile += "(deny default)\n"; ++ } else { ++ sandboxProfile += "(deny default (with no-log))\n"; ++ } + +- /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ +- sandboxProfile += "(allow file-read*\n"; +- for (auto & i : ancestry) { +- sandboxProfile += fmt("\t(literal \"%s\")\n", i); +- } +- sandboxProfile += ")\n"; ++ sandboxProfile += ++ #include "sandbox-defaults.sb" ++ ; + +- sandboxProfile += additionalSandboxProfile; +- } else ++ if (!derivationType->isSandboxed()) + sandboxProfile += +- #include "sandbox-minimal.sb" ++ #include "sandbox-network.sb" + ; + +- debug("Generated sandbox profile:"); +- debug(sandboxProfile); +- +- Path sandboxFile = tmpDir + "/.sandbox.sb"; ++ /* Add the output paths we'll use at build-time to the chroot */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & [_, path] : scratchOutputs) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", worker.store.printStorePath(path)); + +- writeFile(sandboxFile, sandboxProfile); ++ sandboxProfile += ")\n"; + +- bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ /* Our inputs (transitive dependencies and any impurities computed above) + +- /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms +- to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ +- Path globalTmpDir = canonPath(defaultTempDir(), true); ++ without file-write* allowed, access() incorrectly returns EPERM ++ */ ++ sandboxProfile += "(allow file-read* file-write* process-exec\n"; ++ for (auto & i : pathsInChroot) { ++ if (i.first != i.second.source) ++ throw Error( ++ "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", ++ i.first, i.second.source); ++ ++ std::string path = i.first; ++ auto optSt = maybeLstat(path.c_str()); ++ if (!optSt) { ++ if (i.second.optional) ++ continue; ++ throw SysError("getting attributes of required path '%s", path); ++ } ++ if (S_ISDIR(optSt->st_mode)) ++ sandboxProfile += fmt("\t(subpath \"%s\")\n", path); ++ else ++ sandboxProfile += fmt("\t(literal \"%s\")\n", path); ++ } ++ sandboxProfile += ")\n"; + +- /* They don't like trailing slashes on subpath directives */ +- while (!globalTmpDir.empty() && globalTmpDir.back() == '/') +- globalTmpDir.pop_back(); ++ /* Allow file-read* on full directory hierarchy to self. Allows realpath() */ ++ sandboxProfile += "(allow file-read*\n"; ++ for (auto & i : ancestry) { ++ sandboxProfile += fmt("\t(literal \"%s\")\n", i); ++ } ++ sandboxProfile += ")\n"; + +- if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { +- builder = "/usr/bin/sandbox-exec"; +- args.push_back("sandbox-exec"); +- args.push_back("-f"); +- args.push_back(sandboxFile); +- args.push_back("-D"); +- args.push_back("_GLOBAL_TMP_DIR=" + globalTmpDir); +- if (allowLocalNetworking) { +- args.push_back("-D"); +- args.push_back(std::string("_ALLOW_LOCAL_NETWORKING=1")); +- } +- args.push_back(drv->builder); +- } else { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); ++ sandboxProfile += additionalSandboxProfile; ++ } else ++ sandboxProfile += ++ #include "sandbox-minimal.sb" ++ ; ++ ++ debug("Generated sandbox profile:"); ++ debug(sandboxProfile); ++ ++ bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); ++ ++ /* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms ++ to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */ ++ Path globalTmpDir = canonPath(defaultTempDir(), true); ++ ++ /* They don't like trailing slashes on subpath directives */ ++ while (!globalTmpDir.empty() && globalTmpDir.back() == '/') ++ globalTmpDir.pop_back(); ++ ++ if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { ++ Strings sandboxArgs; ++ sandboxArgs.push_back("_GLOBAL_TMP_DIR"); ++ sandboxArgs.push_back(globalTmpDir); ++ if (allowLocalNetworking) { ++ sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); ++ sandboxArgs.push_back("1"); ++ } ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { ++ writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ _exit(1); + } + } ++ ++ builder = drv->builder; ++ args.push_back(std::string(baseNameOf(drv->builder))); + #else +- else { ++ if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/git/0003-packaging-Add-darwin-lsandbox-in-meson.patch b/pkgs/tools/package-management/nix/patches/git/0003-packaging-Add-darwin-lsandbox-in-meson.patch new file mode 100644 index 0000000000000..0dfbd10ab1e89 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/git/0003-packaging-Add-darwin-lsandbox-in-meson.patch @@ -0,0 +1,53 @@ +From f7335530619f9b18d6cc249a297e4dca369101a5 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:23:17 +0200 +Subject: [PATCH 3/6] packaging: Add darwin -lsandbox in meson +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + src/libstore/meson.build | 5 +++++ + src/libstore/package.nix | 2 ++ + 2 files changed, 7 insertions(+) + +diff --git a/src/libstore/meson.build b/src/libstore/meson.build +index 6a6aabf97..c2aa5bff3 100644 +--- a/src/libstore/meson.build ++++ b/src/libstore/meson.build +@@ -69,6 +69,11 @@ has_acl_support = cxx.has_header('sys/xattr.h') \ + and cxx.has_function('lremovexattr') + configdata.set('HAVE_ACL_SUPPORT', has_acl_support.to_int()) + ++if host_machine.system() == 'darwin' ++ sandbox = cxx.find_library('sandbox') ++ deps_other += [sandbox] ++endif ++ + subdir('build-utils-meson/threads') + + boost = dependency( +diff --git a/src/libstore/package.nix b/src/libstore/package.nix +index 9568462b5..f04e3b95f 100644 +--- a/src/libstore/package.nix ++++ b/src/libstore/package.nix +@@ -3,6 +3,7 @@ + , mkMesonLibrary + + , unixtools ++, darwin + + , nix-util + , boost +@@ -56,6 +57,7 @@ mkMesonLibrary (finalAttrs: { + sqlite + ] ++ lib.optional stdenv.hostPlatform.isLinux libseccomp + # There have been issues building these dependencies ++ ++ lib.optional stdenv.hostPlatform.isDarwin darwin.apple_sdk.libs.sandbox + ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform && (stdenv.isLinux || stdenv.isDarwin)) + aws-sdk-cpp + ; +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/git/0004-local-derivation-goal-Print-sandbox-error-detail-on-.patch b/pkgs/tools/package-management/nix/patches/git/0004-local-derivation-goal-Print-sandbox-error-detail-on-.patch new file mode 100644 index 0000000000000..4bff61efdf7f0 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/git/0004-local-derivation-goal-Print-sandbox-error-detail-on-.patch @@ -0,0 +1,34 @@ +From 14d09e0b55898ac22d4cdeade3bf6c4174052ffd Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:44:12 +0200 +Subject: [PATCH 4/6] local-derivation-goal: Print sandbox error detail on + darwin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index 067755c0d..f34d68403 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2208,8 +2208,9 @@ void LocalDerivationGoal::runChild() + sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING"); + sandboxArgs.push_back("1"); + } +- if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) { +- writeFull(STDERR_FILENO, "failed to configure sandbox\n"); ++ char * sandbox_errbuf = nullptr; ++ if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), &sandbox_errbuf)) { ++ writeFull(STDERR_FILENO, fmt("failed to configure sandbox: %s\n", sandbox_errbuf ? sandbox_errbuf : "(null)")); + _exit(1); + } + } +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/git/0005-local-derivation-goal-Refactor.patch b/pkgs/tools/package-management/nix/patches/git/0005-local-derivation-goal-Refactor.patch new file mode 100644 index 0000000000000..cec9d67513ed6 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/git/0005-local-derivation-goal-Refactor.patch @@ -0,0 +1,41 @@ +From 06e27042e176b79561f50decb0fdf836b7bec3f5 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:50:27 +0200 +Subject: [PATCH 5/6] local-derivation-goal: Refactor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This works because the `builder` and `args` variables are only used +in the non-builtin code path. + +Co-Authored-By: Théophane Hufschmitt +Signed-off-by: Jörg Thalheim +--- + src/libstore/unix/build/local-derivation-goal.cc | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index f34d68403..f781a84c6 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2214,15 +2214,12 @@ void LocalDerivationGoal::runChild() + _exit(1); + } + } ++#endif + +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +-#else + if (!drv->isBuiltin()) { + builder = drv->builder; + args.push_back(std::string(baseNameOf(drv->builder))); + } +-#endif + + for (auto & i : drv->args) + args.push_back(rewriteStrings(i, inputRewrites)); +-- +2.46.1 + diff --git a/pkgs/tools/package-management/nix/patches/git/0006-local-derivation-goal-Move-builder-preparation-to-no.patch b/pkgs/tools/package-management/nix/patches/git/0006-local-derivation-goal-Move-builder-preparation-to-no.patch new file mode 100644 index 0000000000000..4e63db1f183e1 --- /dev/null +++ b/pkgs/tools/package-management/nix/patches/git/0006-local-derivation-goal-Move-builder-preparation-to-no.patch @@ -0,0 +1,75 @@ +From d1e0bae55afb3c3ef0bcad5d644b0e04da6279b3 Mon Sep 17 00:00:00 2001 +From: Robert Hensing +Date: Thu, 3 Oct 2024 12:57:00 +0200 +Subject: [PATCH 6/6] local-derivation-goal: Move builder preparation to + non-builtin code path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + .../unix/build/local-derivation-goal.cc | 25 ++++++++----------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc +index f781a84c6..dcfaadeef 100644 +--- a/src/libstore/unix/build/local-derivation-goal.cc ++++ b/src/libstore/unix/build/local-derivation-goal.cc +@@ -2087,11 +2087,6 @@ void LocalDerivationGoal::runChild() + throw SysError("setuid failed"); + } + +- /* Fill in the arguments. */ +- Strings args; +- +- std::string builder = "invalid"; +- + #if __APPLE__ + /* This has to appear before import statements. */ + std::string sandboxProfile = "(version 1)\n"; +@@ -2216,14 +2211,6 @@ void LocalDerivationGoal::runChild() + } + #endif + +- if (!drv->isBuiltin()) { +- builder = drv->builder; +- args.push_back(std::string(baseNameOf(drv->builder))); +- } +- +- for (auto & i : drv->args) +- args.push_back(rewriteStrings(i, inputRewrites)); +- + /* Indicate that we managed to set up the build environment. */ + writeFull(STDERR_FILENO, std::string("\2\n")); + +@@ -2254,6 +2241,14 @@ void LocalDerivationGoal::runChild() + } + } + ++ // Now builder is not builtin ++ ++ Strings args; ++ args.push_back(std::string(baseNameOf(drv->builder))); ++ ++ for (auto & i : drv->args) ++ args.push_back(rewriteStrings(i, inputRewrites)); ++ + #if __APPLE__ + posix_spawnattr_t attrp; + +@@ -2275,9 +2270,9 @@ void LocalDerivationGoal::runChild() + posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); + } + +- posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ posix_spawn(NULL, drv->builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #else +- execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); ++ execve(drv->builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + #endif + + throw SysError("executing '%1%'", drv->builder); +-- +2.46.1 +