1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 22:11:15 +02:00

libstore: Don't default build-dir to temp-dir, store setting

If a build directory is accessible to other users it is possible to
smuggle data in and out of build directories. Usually this is only
a build purity problem, but in combination with other issues it can
be used to break out of a build sandbox. to prevent this we default
to using a subdirectory of nixStateDir (which is more restrictive).

(cherry picked from pennae Lix commit 55b416f6897fb0d8a9315a530a9b7f0914458ded)
(store setting done by roberth)
This commit is contained in:
eldritch horrors 2025-03-30 16:45:34 +02:00 committed by Jörg Thalheim
parent 9af4c267c6
commit 88b7db1ba4
11 changed files with 62 additions and 15 deletions

View file

@ -0,0 +1,9 @@
---
synopsis: "`build-dir` no longer defaults to `$TMPDIR`"
---
The directory in which temporary build directories are created no longer defaults
to `TMPDIR` or `/tmp`, to avoid builders making their directories
world-accessible. This behavior allowed escaping the build sandbox and can
cause build impurities even when not used maliciously. We now default to `builds`
in `NIX_STATE_DIR` (which is `/nix/var/nix/builds` in the default configuration).

View file

@ -1 +1,2 @@
d @localstatedir@/nix/daemon-socket 0755 root root - -
d @localstatedir@/nix/daemon-socket 0755 root root - -
d @localstatedir@/nix/builds 0755 root root 7d -

View file

@ -6,6 +6,7 @@
#include "nix/util/abstract-setting-to-json.hh"
#include "nix/util/compute-levels.hh"
#include "nix/util/signals.hh"
#include "nix/util/types.hh"
#include <algorithm>
#include <map>

View file

@ -697,14 +697,7 @@ public:
Setting<std::optional<Path>> buildDir{this, std::nullopt, "build-dir",
R"(
The directory on the host, in which derivations' temporary build directories are created.
If not set, Nix uses the system temporary directory indicated by the `TMPDIR` environment variable.
Note that builds are often performed by the Nix daemon, so its `TMPDIR` is used, and not that of the Nix command line interface.
This is also the location where [`--keep-failed`](@docroot@/command-ref/opt-common.md#opt-keep-failed) leaves its files.
If Nix runs without sandbox, or if the platform does not support sandboxing with bind mounts (e.g. macOS), then the [`builder`](@docroot@/language/derivations.md#attr-builder)'s environment contains this directory instead of the virtual location [`sandbox-build-dir`](#conf-sandbox-build-dir).
Override the `build-dir` store setting for all stores that have this setting.
)"};
Setting<PathSet> allowedImpureHostPrefixes{this, {}, "allowed-impure-host-deps",

View file

@ -34,7 +34,38 @@ struct OptimiseStats
uint64_t bytesFreed = 0;
};
struct LocalStoreConfig : std::enable_shared_from_this<LocalStoreConfig>, virtual LocalFSStoreConfig
struct LocalBuildStoreConfig : virtual LocalFSStoreConfig {
private:
/**
Input for computing the build directory. See `getBuildDir()`.
*/
Setting<std::optional<Path>> buildDir{this, std::nullopt, "build-dir",
R"(
The directory on the host, in which derivations' temporary build directories are created.
If not set, Nix will use the `builds` subdirectory of its configured state directory.
Note that builds are often performed by the Nix daemon, so its `build-dir` applies.
Nix will create this directory automatically with suitable permissions if it does not exist.
Otherwise its permissions must allow all users to traverse the directory (i.e. it must have `o+x` set, in unix parlance) for non-sandboxed builds to work correctly.
This is also the location where [`--keep-failed`](@docroot@/command-ref/opt-common.md#opt-keep-failed) leaves its files.
If Nix runs without sandbox, or if the platform does not support sandboxing with bind mounts (e.g. macOS), then the [`builder`](@docroot@/language/derivations.md#attr-builder)'s environment will contain this directory, instead of the virtual location [`sandbox-build-dir`](#conf-sandbox-build-dir).
> **Warning**
>
> `build-dir` must not be set to a world-writable directory.
> Placing temporary build directories in a world-writable place allows other users to access or modify build data that is currently in use.
> This alone is merely an impurity, but combined with another factor this has allowed malicious derivations to escape the build sandbox.
)"};
public:
Path getBuildDir() const;
};
struct LocalStoreConfig : std::enable_shared_from_this<LocalStoreConfig>, virtual LocalFSStoreConfig, virtual LocalBuildStoreConfig
{
using LocalFSStoreConfig::LocalFSStoreConfig;

View file

@ -77,6 +77,18 @@ std::string LocalStoreConfig::doc()
;
}
Path LocalBuildStoreConfig::getBuildDir() const
{
if (settings.buildDir.get().has_value()) {
return *settings.buildDir.get();
}
if (buildDir.get().has_value()) {
return *buildDir.get();
}
return stateDir.get() + "/builds";
}
ref<Store> LocalStore::Config::openStore() const
{
return make_ref<LocalStore>(ref{shared_from_this()});

View file

@ -725,9 +725,13 @@ void DerivationBuilderImpl::startBuilder()
throw BuildError(msg);
}
auto buildDir = getLocalStore(store).config->getBuildDir();
createDirs(buildDir);
/* Create a temporary directory where the build will take
place. */
topTmpDir = createTempDir(settings.buildDir.get().value_or(""), "nix-build-" + std::string(drvPath.name()), 0700);
topTmpDir = createTempDir(buildDir, "nix-build-" + std::string(drvPath.name()), 0700);
setBuildTmpDir();
assert(!tmpDir.empty());

View file

@ -12,7 +12,6 @@ requiresUnprivilegedUserNamespaces
[[ $busybox =~ busybox ]] || skipTest "no busybox"
unset NIX_STORE_DIR
unset NIX_STATE_DIR
# We first build a dependency of the derivation we eventually want to
# build.

View file

@ -9,7 +9,6 @@ requiresUnprivilegedUserNamespaces
[[ "$busybox" =~ busybox ]] || skipTest "no busybox"
unset NIX_STORE_DIR
unset NIX_STATE_DIR
remoteDir=$TEST_ROOT/remote

View file

@ -8,7 +8,6 @@ requiresUnprivilegedUserNamespaces
# Avoid store dir being inside sandbox build-dir
unset NIX_STORE_DIR
unset NIX_STATE_DIR
function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }

View file

@ -14,7 +14,6 @@ execUnshare <<EOF
# Avoid store dir being inside sandbox build-dir
unset NIX_STORE_DIR
unset NIX_STATE_DIR
setLocalStore () {
export NIX_REMOTE=\$TEST_ROOT/\$1