diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index adf816494..87aeb4f2d 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -37,7 +37,7 @@ EvalSettings evalSettings { auto [accessor, lockedRef] = flakeRef.resolve(state.store).lazyFetch(state.store); auto storePath = nix::fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy, lockedRef.input.getName()); state.allowPath(storePath); - return state.rootPath(state.store->toRealPath(storePath)); + return state.rootPath(state.store->printStorePath(storePath)); }, }, }, @@ -179,7 +179,7 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * bas state.fetchSettings, EvalSettings::resolvePseudoUrl(s)); auto storePath = fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy); - return state.rootPath(CanonPath(state.store->toRealPath(storePath))); + return state.rootPath(CanonPath(state.store->printStorePath(storePath))); } else if (hasPrefix(s, "flake:")) { @@ -188,7 +188,7 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s, const Path * bas auto [accessor, lockedRef] = flakeRef.resolve(state.store).lazyFetch(state.store); auto storePath = nix::fetchToStore(*state.store, SourcePath(accessor), FetchMode::Copy, lockedRef.input.getName()); state.allowPath(storePath); - return state.rootPath(CanonPath(state.store->toRealPath(storePath))); + return state.rootPath(CanonPath(state.store->printStorePath(storePath))); } else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index efffc69f1..ab2eb98e5 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -246,21 +246,37 @@ EvalState::EvalState( , repair(NoRepair) , emptyBindings(0) , rootFS( - settings.restrictEval || settings.pureEval - ? ref(AllowListSourceAccessor::create(getFSSourceAccessor(), {}, - [&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); - })) - : getFSSourceAccessor()) - , storeFS( - makeMountedSourceAccessor( - { - {CanonPath::root, makeEmptySourceAccessor()}, - {CanonPath(store->storeDir), makeFSSourceAccessor(dirOf(store->toRealPath(StorePath::dummy)))} - })) + ({ + auto accessor = getFSSourceAccessor(); + + /* If we have a chroot store, make 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 realStoreDir = dirOf(store->toRealPath(StorePath::dummy)); + if (store->storeDir != realStoreDir) { + auto storeFS = makeMountedSourceAccessor( + { + {CanonPath::root, makeEmptySourceAccessor()}, + {CanonPath(store->storeDir), makeFSSourceAccessor(realStoreDir)} + }); + accessor = 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; + })) , corepkgsFS(make_ref()) , internalFS(make_ref()) , derivationInternal{corepkgsFS->addFile( @@ -350,7 +366,7 @@ void EvalState::allowPath(const Path & path) void EvalState::allowPath(const StorePath & storePath) { if (auto rootFS2 = rootFS.dynamic_pointer_cast()) - rootFS2->allowPrefix(CanonPath(store->toRealPath(storePath))); + rootFS2->allowPrefix(CanonPath(store->printStorePath(storePath))); } void EvalState::allowClosure(const StorePath & storePath) @@ -2428,7 +2444,7 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned(); if (path == "" || path[0] != '/') error("string '%1%' doesn't represent an absolute path", path).withTrace(pos, errorCtx).debugThrow(); - return stringWithContextToPath(path, context); + return rootPath(path); } @@ -3082,7 +3098,7 @@ std::optional EvalState::resolveLookupPathPath(const LookupPath::Pat fetchSettings, EvalSettings::resolvePseudoUrl(value)); auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy); - return finish(rootPath(store->toRealPath(storePath))); + return finish(rootPath(store->printStorePath(storePath))); } catch (Error & e) { logWarning({ .msg = HintFmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 6a601a587..aca2e8bfd 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -250,11 +250,6 @@ public: */ const ref rootFS; - /** - * The accessor for the store. - */ - const ref storeFS; - /** * The in-memory filesystem for paths. */ @@ -394,18 +389,6 @@ public: */ SourcePath rootPath(PathView path); - /** - * Convert `s` to a path. If `context` is not empty, the resulting - * path will use the `storeFS` accessor; otherwise it will use - * `rootFS`. When using a chroot store, this allows us to - * distinguish between store paths resulting from - * import-from-derivation and sources stored in the actual - * /nix/store. - */ - SourcePath stringWithContextToPath( - std::string_view s, - const NixStringContext & context); - /** * Allow access to a path. */ diff --git a/src/libexpr/paths.cc b/src/libexpr/paths.cc index ea28b5a7e..474ea2d74 100644 --- a/src/libexpr/paths.cc +++ b/src/libexpr/paths.cc @@ -13,10 +13,4 @@ SourcePath EvalState::rootPath(PathView path) return {rootFS, CanonPath(absPath(path))}; } -SourcePath EvalState::stringWithContextToPath(std::string_view s, const NixStringContext & context) -{ - auto path = CanonPath(s); - return !context.empty() ? SourcePath{storeFS, std::move(path)} : rootPath(std::move(path)); -} - } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 88d09e563..87f7eeb18 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -143,7 +143,7 @@ static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, st auto path = state.coerceToPath(noPos, v, context, "while realising the context of a path"); try { - if (!context.empty() && path.accessor == state.storeFS) { + if (!context.empty() && path.accessor == state.rootFS) { auto rewrites = state.realiseContext(context); path = {path.accessor, CanonPath(rewriteStrings(path.path.abs(), rewrites))}; } @@ -2480,7 +2480,7 @@ static void addPath( try { StorePathSet refs; - if (path.accessor == state.storeFS && state.store->isInStore(path.path.abs())) { + if (path.accessor == state.rootFS && state.store->isInStore(path.path.abs())) { // FIXME: handle CA derivation outputs (where path needs to // be rewritten to the actual output). auto rewrites = state.realiseContext(context); diff --git a/src/libflake/flake/flake.cc b/src/libflake/flake/flake.cc index ec0c8dde9..eebd6ec2d 100644 --- a/src/libflake/flake/flake.cc +++ b/src/libflake/flake/flake.cc @@ -337,7 +337,7 @@ static Flake readFlake( auto storePath = fetchToStore(*state.store, setting.value->path(), FetchMode::Copy); flake.config.settings.emplace( state.symbols[setting.name], - state.store->toRealPath(storePath)); + state.store->printStorePath(storePath)); } else if (setting.value->type() == nInt) flake.config.settings.emplace( @@ -423,7 +423,7 @@ static Flake getFlake( auto storePath = copyInputToStore(state, lockedRef.input, originalRef.input, accessor); // Re-parse flake.nix from the store. - return readFlake(state, originalRef, resolvedRef, lockedRef, state.rootPath(state.store->toRealPath(storePath)), lockRootAttrPath); + return readFlake(state, originalRef, resolvedRef, lockedRef, state.rootPath(state.store->printStorePath(storePath)), lockRootAttrPath); } Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries) @@ -784,7 +784,7 @@ LockedFlake lockFlake( // FIXME: allow input to be lazy. auto storePath = copyInputToStore(state, lockedRef.input, input.ref->input, accessor); - return {state.rootPath(state.store->toRealPath(storePath)), lockedRef}; + return {state.rootPath(state.store->printStorePath(storePath)), lockedRef}; } }();