From ef5689dc1b240d9827388074c9a04c8d87781578 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 (cherry picked from commit 9d99a7c2cfd9f18ca3e7fa24ce34a7b5e39af3d4) --- .../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 01bb14634..b2ef30db7 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -459,6 +459,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")