1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 10:41:16 +02:00

Use UnionSourceAccessor to mount the chroot store on top of the real store directory

This commit is contained in:
Eelco Dolstra 2025-02-19 12:46:22 +01:00
parent 5b7c240ebd
commit 99e78c37f7
6 changed files with 42 additions and 49 deletions

View file

@ -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) == '>') {

View file

@ -246,20 +246,36 @@ EvalState::EvalState(
, repair(NoRepair)
, emptyBindings(0)
, rootFS(
settings.restrictEval || settings.pureEval
? ref<SourceAccessor>(AllowListSourceAccessor::create(getFSSourceAccessor(), {},
({
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);
}))
: getFSSourceAccessor())
, storeFS(
makeMountedSourceAccessor(
{
{CanonPath::root, makeEmptySourceAccessor()},
{CanonPath(store->storeDir), makeFSSourceAccessor(dirOf(store->toRealPath(StorePath::dummy)))}
});
accessor;
}))
, corepkgsFS(make_ref<MemorySourceAccessor>())
, internalFS(make_ref<MemorySourceAccessor>())
@ -350,7 +366,7 @@ void EvalState::allowPath(const Path & path)
void EvalState::allowPath(const StorePath & storePath)
{
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListSourceAccessor>())
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<EvalError>("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<SourcePath> 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)

View file

@ -250,11 +250,6 @@ public:
*/
const ref<SourceAccessor> rootFS;
/**
* The accessor for the store.
*/
const ref<SourceAccessor> storeFS;
/**
* The in-memory filesystem for <nix/...> 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.
*/

View file

@ -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));
}
}

View file

@ -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);

View file

@ -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};
}
}();