From 9d99a7c2cfd9f18ca3e7fa24ce34a7b5e39af3d4 Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Sun, 2 Mar 2025 15:07:45 +0100 Subject: [PATCH] libexpr: fix checkSourcePath purity regression Starting with commit 0dbfa7b26eeee39624d25593cf457070d6296319 access would also be allowed to ancestors of allowed paths. This is (ironically) a significant purity regression, since several users of the purity checks will themselves assume that arbitrary descent is allowed. For example, `builtins.readDir` and `builtins.path` could now refer to the filesystem root, breaking purity entirely in the latter case by allowing to read arbitrary files. Restore the previous behaviour of only allowing access to explicitly allowed paths. Change-Id: Ie64180733ab735da9873255e1ccbf95ba7c9161c --- .../rl-next/checkSourcePath-purity-regression.md | 15 +++++++++++++++ lix/libexpr/eval.cc | 4 ++++ tests/functional/pure-eval.sh | 1 + 3 files changed, 20 insertions(+) create mode 100644 doc/manual/rl-next/checkSourcePath-purity-regression.md diff --git a/doc/manual/rl-next/checkSourcePath-purity-regression.md b/doc/manual/rl-next/checkSourcePath-purity-regression.md new file mode 100644 index 000000000..0d4ac48b7 --- /dev/null +++ b/doc/manual/rl-next/checkSourcePath-purity-regression.md @@ -0,0 +1,15 @@ +--- +synopsis: Forbid impure path accesses in pure evaluation mode again +category: Fixes +cls: [2708] +credits: [alois31] +--- +Lix 2.92.0 mistakenly started allowing the access to ancestors of allowed paths in pure evaluation mode. +This made it possible to bypass the purity restrictions, for example by copying arbitrary files to the store: +```nix +builtins.path { + path = "/"; + filter = …; +} +``` +Restore the previous behaviour of prohibiting such impure accesses. diff --git a/lix/libexpr/eval.cc b/lix/libexpr/eval.cc index ea493294b..211c1cb7e 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -464,6 +464,10 @@ retry: } current = std::move(next); } + // Downstream users (e.g. `builtins.readDir` or `builtins.path`) will want to descend. + if (level && !level->allowAllChildren) { + goto failed; + } resolvedPaths.insert_or_assign(path_.canonical().abs(), current); return current; diff --git a/tests/functional/pure-eval.sh b/tests/functional/pure-eval.sh index ace1db001..7940c43b7 100644 --- a/tests/functional/pure-eval.sh +++ b/tests/functional/pure-eval.sh @@ -18,6 +18,7 @@ echo "$missingImpureErrorMsg" | grepQuiet -- --impure || \ (! nix eval --expr builtins.currentSystem) (! nix-instantiate --pure-eval ./simple.nix) +(! nix eval --expr 'builtins.readDir "/"') [[ $(nix eval --impure --expr "(import (builtins.fetchurl { url = \"file://$(pwd)/pure-eval.nix\"; })).x") == 123 ]] (! nix eval --expr "(import (builtins.fetchurl { url = \"file://$(pwd)/pure-eval.nix\"; })).x")