1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-10 11:01:03 +01:00

Add a special type of context for the result of toString

When you apply `builtins.toString` to a path value representing a path
in the Nix store (as is the case with flake inputs), historically you
got a string without context (e.g. `/nix/store/...-source`). This is
broken, since it allows you to pass a store path to a
derivation/toFile without a proper store reference. This is especially
a problem with lazy trees, since the store path is a virtual path that
doesn't exist and can be different every time.

For backwards compatibility, and to warn users about this unsafe use
of `toString`, we now keep track of such strings as a special type of
context.
This commit is contained in:
Eelco Dolstra 2025-05-07 18:53:39 +02:00
parent 8c568277fd
commit 2a35d8f800
10 changed files with 129 additions and 10 deletions

View file

@ -952,8 +952,8 @@ void EvalState::mkPos(Value & v, PosIdx p)
// FIXME: only do this for virtual store paths?
attrs.alloc(sFile).mkString(path->path.abs(),
{
NixStringContextElem::Opaque{
.path = store->toStorePath(path->path.abs()).first
NixStringContextElem::Path{
.storePath = store->toStorePath(path->path.abs()).first
}
});
else
@ -2277,7 +2277,10 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos, std::s
{
auto s = forceString(v, pos, errorCtx);
if (v.context()) {
error<EvalError>("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string_view(), v.context()[0]).withTrace(pos, errorCtx).debugThrow();
NixStringContext context;
copyContext(v, context);
if (hasContext(context))
error<EvalError>("the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string_view(), v.context()[0]).withTrace(pos, errorCtx).debugThrow();
}
return s;
}
@ -2336,7 +2339,16 @@ BackedStringView EvalState::coerceToString(
v.payload.path.path
: copyToStore
? store->printStorePath(copyPathToStore(context, v.path()))
: std::string(v.path().path.abs());
: ({
auto path = v.path();
if (path.accessor == rootFS && store->isInStore(path.path.abs())) {
context.insert(
NixStringContextElem::Path{
.storePath = store->toStorePath(path.path.abs()).first
});
}
std::string(path.path.abs());
});
}
if (v.type() == nAttrs) {
@ -2499,6 +2511,9 @@ std::pair<SingleDerivedPath, std::string_view> EvalState::coerceToSingleDerivedP
[&](NixStringContextElem::Built && b) -> SingleDerivedPath {
return std::move(b);
},
[&](NixStringContextElem::Path && p) -> SingleDerivedPath {
abort(); // FIXME
},
}, ((NixStringContextElem &&) *context.begin()).raw);
return {
std::move(derivedPath),