From 59fb0a72c6fa83f8e4ef809c265bdd86cdbc6563 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 1 Apr 2025 15:19:46 +0200 Subject: [PATCH] Apply makeNotAllowedError to empty repos (cherry picked from commit 67e957b636d7e038c58bb21febd3493984c61d04) # Conflicts: # src/libexpr/eval.cc # tests/functional/flakes/meson.build --- src/libexpr/eval.cc | 39 ++++++++++++++++++++ src/libfetchers/filtering-source-accessor.cc | 14 ++++++- src/libfetchers/filtering-source-accessor.hh | 3 ++ src/libfetchers/git-utils.cc | 12 ++---- tests/functional/flakes/meson.build | 6 +++ tests/functional/flakes/source-paths.sh | 23 ++++++++++++ 6 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 tests/functional/flakes/source-paths.sh diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index ba67d0679..6198023e0 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -246,6 +246,7 @@ EvalState::EvalState( , repair(NoRepair) , emptyBindings(0) , rootFS( +<<<<<<< HEAD settings.restrictEval || settings.pureEval ? ref(AllowListSourceAccessor::create(getFSSourceAccessor(), {}, [&settings](const CanonPath & path) -> RestrictedPathError { @@ -255,6 +256,44 @@ EvalState::EvalState( throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation); })) : getFSSourceAccessor()) +======= + ({ + /* In pure eval mode, we provide a filesystem that only + contains the Nix store. + + If we have a chroot store and pure eval is not enabled, + use a union accessor to make the chroot store available + at its logical location while still having the + underlying directory available. This is necessary for + instance if we're evaluating a file from the physical + /nix/store while using a chroot store. */ + auto accessor = getFSSourceAccessor(); + + auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy)); + if (settings.pureEval || store->storeDir != realStoreDir) { + auto storeFS = makeMountedSourceAccessor( + { + {CanonPath::root, makeEmptySourceAccessor()}, + {CanonPath(store->storeDir), makeFSSourceAccessor(realStoreDir)} + }); + accessor = settings.pureEval + ? storeFS + : makeUnionSourceAccessor({accessor, storeFS}); + } + + /* Apply access control if needed. */ + if (settings.restrictEval || settings.pureEval) + accessor = AllowListSourceAccessor::create(accessor, {}, {}, + [&settings](const CanonPath & path) -> RestrictedPathError { + auto modeInformation = settings.pureEval + ? "in pure evaluation mode (use '--impure' to override)" + : "in restricted mode"; + throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation); + }); + + accessor; + })) +>>>>>>> 67e957b63 (Apply makeNotAllowedError to empty repos) , corepkgsFS(make_ref()) , internalFS(make_ref()) , derivationInternal{corepkgsFS->addFile( diff --git a/src/libfetchers/filtering-source-accessor.cc b/src/libfetchers/filtering-source-accessor.cc index d4557b6d4..c6a00faef 100644 --- a/src/libfetchers/filtering-source-accessor.cc +++ b/src/libfetchers/filtering-source-accessor.cc @@ -58,18 +58,23 @@ void FilteringSourceAccessor::checkAccess(const CanonPath & path) struct AllowListSourceAccessorImpl : AllowListSourceAccessor { std::set allowedPrefixes; + std::unordered_set allowedPaths; AllowListSourceAccessorImpl( ref next, std::set && allowedPrefixes, + std::unordered_set && allowedPaths, MakeNotAllowedError && makeNotAllowedError) : AllowListSourceAccessor(SourcePath(next), std::move(makeNotAllowedError)) , allowedPrefixes(std::move(allowedPrefixes)) + , allowedPaths(std::move(allowedPaths)) { } bool isAllowed(const CanonPath & path) override { - return path.isAllowed(allowedPrefixes); + return + allowedPaths.contains(path) + || path.isAllowed(allowedPrefixes); } void allowPrefix(CanonPath prefix) override @@ -81,9 +86,14 @@ struct AllowListSourceAccessorImpl : AllowListSourceAccessor ref AllowListSourceAccessor::create( ref next, std::set && allowedPrefixes, + std::unordered_set && allowedPaths, MakeNotAllowedError && makeNotAllowedError) { - return make_ref(next, std::move(allowedPrefixes), std::move(makeNotAllowedError)); + return make_ref( + next, + std::move(allowedPrefixes), + std::move(allowedPaths), + std::move(makeNotAllowedError)); } bool CachingFilteringSourceAccessor::isAllowed(const CanonPath & path) diff --git a/src/libfetchers/filtering-source-accessor.hh b/src/libfetchers/filtering-source-accessor.hh index 1f8d84e53..41889cfd7 100644 --- a/src/libfetchers/filtering-source-accessor.hh +++ b/src/libfetchers/filtering-source-accessor.hh @@ -2,6 +2,8 @@ #include "source-path.hh" +#include + namespace nix { /** @@ -70,6 +72,7 @@ struct AllowListSourceAccessor : public FilteringSourceAccessor static ref create( ref next, std::set && allowedPrefixes, + std::unordered_set && allowedPaths, MakeNotAllowedError && makeNotAllowedError); using FilteringSourceAccessor::FilteringSourceAccessor; diff --git a/src/libfetchers/git-utils.cc b/src/libfetchers/git-utils.cc index a6b13fb31..484fc37a0 100644 --- a/src/libfetchers/git-utils.cc +++ b/src/libfetchers/git-utils.cc @@ -1214,16 +1214,12 @@ ref GitRepoImpl::getAccessor( ref GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError) { auto self = ref(shared_from_this()); - /* In case of an empty workdir, return an empty in-memory tree. We - cannot use AllowListSourceAccessor because it would return an - error for the root (and we can't add the root to the allow-list - since that would allow access to all its children). */ ref fileAccessor = - wd.files.empty() - ? makeEmptySourceAccessor() - : AllowListSourceAccessor::create( + AllowListSourceAccessor::create( makeFSSourceAccessor(path), - std::set { wd.files }, + std::set{ wd.files }, + // Always allow access to the root, but not its children. + std::unordered_set{CanonPath::root}, std::move(makeNotAllowedError)).cast(); if (exportIgnore) return make_ref(self, fileAccessor, std::nullopt); diff --git a/tests/functional/flakes/meson.build b/tests/functional/flakes/meson.build index cc65dc306..85dffd5e8 100644 --- a/tests/functional/flakes/meson.build +++ b/tests/functional/flakes/meson.build @@ -28,6 +28,12 @@ suites += { 'commit-lock-file-summary.sh', 'non-flake-inputs.sh', 'relative-paths.sh', +<<<<<<< HEAD +======= + 'symlink-paths.sh', + 'debugger.sh', + 'source-paths.sh', +>>>>>>> 67e957b63 (Apply makeNotAllowedError to empty repos) ], 'workdir': meson.current_source_dir(), } diff --git a/tests/functional/flakes/source-paths.sh b/tests/functional/flakes/source-paths.sh new file mode 100644 index 000000000..4709bf2fc --- /dev/null +++ b/tests/functional/flakes/source-paths.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +source ./common.sh + +requireGit + +repo=$TEST_ROOT/repo + +createGitRepo "$repo" + +cat > "$repo/flake.nix" <