diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2018-08-03T15·01+0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-03T15·01+0200 |
commit | bc65e02d9671ef6af2c25b4cc7a0a34944d98a2d (patch) | |
tree | 3a120d4eaa1c63dfbcbd19b0a3835069aceed217 | |
parent | 122e1a61f8deb55a38a00534c502fd8c6700d539 (diff) | |
parent | 43e28a1b756c2f7ee139c999e6169a71f555e9e5 (diff) |
Merge pull request #2326 from aszlig/fix-symlink-leak
Fix symlink leak in restricted eval mode
-rw-r--r-- | src/libexpr/eval.cc | 14 | ||||
-rw-r--r-- | tests/restricted.sh | 11 |
2 files changed, 21 insertions, 4 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 095320dc8515..f41905787f9e 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -349,19 +349,25 @@ Path EvalState::checkSourcePath(const Path & path_) bool found = false; + /* First canonicalize the path without symlinks, so we make sure an + * attacker can't append ../../... to a path that would be in allowedPaths + * and thus leak symlink targets. + */ + Path abspath = canonPath(path_); + for (auto & i : *allowedPaths) { - if (isDirOrInDir(path_, i)) { + if (isDirOrInDir(abspath, i)) { found = true; break; } } if (!found) - throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", path_); + throw RestrictedPathError("access to path '%1%' is forbidden in restricted mode", abspath); /* Resolve symlinks. */ - debug(format("checking access to '%s'") % path_); - Path path = canonPath(path_, true); + debug(format("checking access to '%s'") % abspath); + Path path = canonPath(abspath, true); for (auto & i : *allowedPaths) { if (isDirOrInDir(path, i)) { diff --git a/tests/restricted.sh b/tests/restricted.sh index a87d8ec2c940..e02becc60e38 100644 --- a/tests/restricted.sh +++ b/tests/restricted.sh @@ -38,3 +38,14 @@ ln -sfn $(pwd)/restricted.nix $TEST_ROOT/restricted.nix nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I $TEST_ROOT -I . [[ $(nix eval --raw --restrict-eval -I . '(builtins.readFile "${import ./simple.nix}/hello")') == 'Hello World!' ]] + +# Check whether we can leak symlink information through directory traversal. +traverseDir="$(pwd)/restricted-traverse-me" +ln -sfn "$(pwd)/restricted-secret" "$(pwd)/restricted-innocent" +mkdir -p "$traverseDir" +goUp="..$(echo "$traverseDir" | sed -e 's,[^/]\+,..,g')" +output="$(nix eval --raw --restrict-eval -I "$traverseDir" \ + "(builtins.readFile \"$traverseDir/$goUp$(pwd)/restricted-innocent\")" \ + 2>&1 || :)" +echo "$output" | grep "is forbidden" +! echo "$output" | grep -F restricted-secret |