mirror of
https://github.com/NixOS/nix
synced 2025-06-27 08:31:16 +02:00
Introduce FSInputAccessor and use it
Backported from the lazy-trees branch. Note that this doesn't yet use the access control features of FSInputAccessor.
This commit is contained in:
parent
e92cac789f
commit
ea38605d11
18 changed files with 502 additions and 126 deletions
|
@ -132,7 +132,7 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
|
|||
if (colon == std::string::npos) fail();
|
||||
std::string filename(fn, 0, colon);
|
||||
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
|
||||
return {CanonPath(fn.substr(0, colon)), lineno};
|
||||
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno};
|
||||
} catch (std::invalid_argument & e) {
|
||||
fail();
|
||||
abort();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "function-trace.hh"
|
||||
#include "profiles.hh"
|
||||
#include "print.hh"
|
||||
#include "fs-input-accessor.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
@ -503,6 +504,18 @@ EvalState::EvalState(
|
|||
, sOutputSpecified(symbols.create("outputSpecified"))
|
||||
, repair(NoRepair)
|
||||
, emptyBindings(0)
|
||||
, rootFS(
|
||||
makeFSInputAccessor(
|
||||
CanonPath::root,
|
||||
evalSettings.restrictEval || evalSettings.pureEval
|
||||
? std::optional<std::set<CanonPath>>(std::set<CanonPath>())
|
||||
: std::nullopt,
|
||||
[](const CanonPath & path) -> RestrictedPathError {
|
||||
auto modeInformation = evalSettings.pureEval
|
||||
? "in pure evaluation mode (use '--impure' to override)"
|
||||
: "in restricted mode";
|
||||
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
|
||||
}))
|
||||
, derivationInternal(rootPath(CanonPath("/builtin/derivation.nix")))
|
||||
, store(store)
|
||||
, buildStore(buildStore ? buildStore : store)
|
||||
|
@ -518,6 +531,8 @@ EvalState::EvalState(
|
|||
, baseEnv(allocEnv(128))
|
||||
, staticBaseEnv{std::make_shared<StaticEnv>(false, nullptr)}
|
||||
{
|
||||
rootFS->allowPath(CanonPath::root); // FIXME
|
||||
|
||||
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
||||
|
||||
assert(gcInitialised);
|
||||
|
@ -599,7 +614,7 @@ SourcePath EvalState::checkSourcePath(const SourcePath & path_)
|
|||
*/
|
||||
Path abspath = canonPath(path_.path.abs());
|
||||
|
||||
if (hasPrefix(abspath, corepkgsPrefix)) return CanonPath(abspath);
|
||||
if (hasPrefix(abspath, corepkgsPrefix)) return rootPath(CanonPath(abspath));
|
||||
|
||||
for (auto & i : *allowedPaths) {
|
||||
if (isDirOrInDir(abspath, i)) {
|
||||
|
@ -617,7 +632,7 @@ SourcePath EvalState::checkSourcePath(const SourcePath & path_)
|
|||
|
||||
/* Resolve symlinks. */
|
||||
debug("checking access to '%s'", abspath);
|
||||
SourcePath path = CanonPath(canonPath(abspath, true));
|
||||
SourcePath path = rootPath(CanonPath(canonPath(abspath, true)));
|
||||
|
||||
for (auto & i : *allowedPaths) {
|
||||
if (isDirOrInDir(path.path.abs(), i)) {
|
||||
|
@ -649,12 +664,12 @@ void EvalState::checkURI(const std::string & uri)
|
|||
/* If the URI is a path, then check it against allowedPaths as
|
||||
well. */
|
||||
if (hasPrefix(uri, "/")) {
|
||||
checkSourcePath(CanonPath(uri));
|
||||
checkSourcePath(rootPath(CanonPath(uri)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasPrefix(uri, "file://")) {
|
||||
checkSourcePath(CanonPath(std::string(uri, 7)));
|
||||
checkSourcePath(rootPath(CanonPath(std::string(uri, 7))));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -950,7 +965,7 @@ void Value::mkStringMove(const char * s, const NixStringContext & context)
|
|||
|
||||
void Value::mkPath(const SourcePath & path)
|
||||
{
|
||||
mkPath(makeImmutableString(path.path.abs()));
|
||||
mkPath(&*path.accessor, makeImmutableString(path.path.abs()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2037,7 +2052,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
|||
else if (firstType == nPath) {
|
||||
if (!context.empty())
|
||||
state.error("a string that refers to a store path cannot be appended to a path").atPos(pos).withFrame(env, *this).debugThrow<EvalError>();
|
||||
v.mkPath(CanonPath(canonPath(str())));
|
||||
v.mkPath(state.rootPath(CanonPath(canonPath(str()))));
|
||||
} else
|
||||
v.mkStringMove(c_str(), context);
|
||||
}
|
||||
|
@ -2236,7 +2251,7 @@ BackedStringView EvalState::coerceToString(
|
|||
!canonicalizePath && !copyToStore
|
||||
? // FIXME: hack to preserve path literals that end in a
|
||||
// slash, as in /foo/${x}.
|
||||
v._path
|
||||
v._path.path
|
||||
: copyToStore
|
||||
? store->printStorePath(copyPathToStore(context, v.path()))
|
||||
: std::string(v.path().path.abs());
|
||||
|
@ -2329,7 +2344,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<EvalError>();
|
||||
return CanonPath(path);
|
||||
return rootPath(CanonPath(path));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2429,7 +2444,9 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
|||
return v1.string_view().compare(v2.string_view()) == 0;
|
||||
|
||||
case nPath:
|
||||
return strcmp(v1._path, v2._path) == 0;
|
||||
return
|
||||
v1._path.accessor == v2._path.accessor
|
||||
&& strcmp(v1._path.path, v2._path.path) == 0;
|
||||
|
||||
case nNull:
|
||||
return true;
|
||||
|
|
|
@ -24,6 +24,7 @@ class EvalState;
|
|||
class StorePath;
|
||||
struct SingleDerivedPath;
|
||||
enum RepairFlag : bool;
|
||||
struct FSInputAccessor;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -211,6 +212,8 @@ public:
|
|||
|
||||
Bindings emptyBindings;
|
||||
|
||||
const ref<FSInputAccessor> rootFS;
|
||||
|
||||
const SourcePath derivationInternal;
|
||||
|
||||
/**
|
||||
|
|
|
@ -223,9 +223,9 @@ static Flake getFlake(
|
|||
throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", lockedRef, lockedRef.subdir);
|
||||
|
||||
Value vInfo;
|
||||
state.evalFile(CanonPath(flakeFile), vInfo, true); // FIXME: symlink attack
|
||||
state.evalFile(state.rootPath(CanonPath(flakeFile)), vInfo, true); // FIXME: symlink attack
|
||||
|
||||
expectType(state, nAttrs, vInfo, state.positions.add({CanonPath(flakeFile)}, 1, 1));
|
||||
expectType(state, nAttrs, vInfo, state.positions.add({state.rootPath(CanonPath(flakeFile))}, 1, 1));
|
||||
|
||||
if (auto description = vInfo.attrs->get(state.sDescription)) {
|
||||
expectType(state, nString, *description->value, description->pos);
|
||||
|
@ -741,7 +741,7 @@ void callFlake(EvalState & state,
|
|||
state.vCallFlake = allocRootValue(state.allocValue());
|
||||
state.eval(state.parseExprFromString(
|
||||
#include "call-flake.nix.gen.hh"
|
||||
, CanonPath::root), **state.vCallFlake);
|
||||
, state.rootPath(CanonPath::root)), **state.vCallFlake);
|
||||
}
|
||||
|
||||
state.callFunction(**state.vCallFlake, *vLocks, *vTmp1, noPos);
|
||||
|
|
|
@ -20,7 +20,6 @@ MakeError(Abort, EvalError);
|
|||
MakeError(TypeError, EvalError);
|
||||
MakeError(UndefinedVarError, Error);
|
||||
MakeError(MissingArgumentError, EvalError);
|
||||
MakeError(RestrictedPathError, Error);
|
||||
|
||||
/**
|
||||
* Position objects.
|
||||
|
@ -200,9 +199,13 @@ struct ExprString : Expr
|
|||
|
||||
struct ExprPath : Expr
|
||||
{
|
||||
ref<InputAccessor> accessor;
|
||||
std::string s;
|
||||
Value v;
|
||||
ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); };
|
||||
ExprPath(ref<InputAccessor> accessor, std::string s) : accessor(accessor), s(std::move(s))
|
||||
{
|
||||
v.mkPath(&*accessor, this->s.c_str());
|
||||
}
|
||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
|
|
@ -64,6 +64,7 @@ struct StringToken {
|
|||
|
||||
#include "parser-tab.hh"
|
||||
#include "lexer-tab.hh"
|
||||
#include "fs-input-accessor.hh"
|
||||
|
||||
YY_DECL;
|
||||
|
||||
|
@ -520,7 +521,7 @@ path_start
|
|||
/* add back in the trailing '/' to the first segment */
|
||||
if ($1.p[$1.l-1] == '/' && $1.l > 1)
|
||||
path += "/";
|
||||
$$ = new ExprPath(std::move(path));
|
||||
$$ = new ExprPath(ref<InputAccessor>(data->state.rootFS), std::move(path));
|
||||
}
|
||||
| HPATH {
|
||||
if (evalSettings.pureEval) {
|
||||
|
@ -530,7 +531,7 @@ path_start
|
|||
);
|
||||
}
|
||||
Path path(getHome() + std::string($1.p + 1, $1.l - 1));
|
||||
$$ = new ExprPath(std::move(path));
|
||||
$$ = new ExprPath(ref<InputAccessor>(data->state.rootFS), std::move(path));
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -756,11 +757,11 @@ SourcePath EvalState::findFile(const SearchPath & searchPath, const std::string_
|
|||
auto r = *rOpt;
|
||||
|
||||
Path res = suffix == "" ? r : concatStrings(r, "/", suffix);
|
||||
if (pathExists(res)) return CanonPath(canonPath(res));
|
||||
if (pathExists(res)) return rootPath(CanonPath(canonPath(res)));
|
||||
}
|
||||
|
||||
if (hasPrefix(path, "nix/"))
|
||||
return CanonPath(concatStrings(corepkgsPrefix, path.substr(4)));
|
||||
return rootPath(CanonPath(concatStrings(corepkgsPrefix, path.substr(4))));
|
||||
|
||||
debugThrow(ThrownError({
|
||||
.msg = hintfmt(evalSettings.pureEval
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "eval.hh"
|
||||
#include "fs-input-accessor.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
SourcePath EvalState::rootPath(CanonPath path)
|
||||
{
|
||||
return path;
|
||||
return {rootFS, std::move(path)};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
|||
state.vImportedDrvToDerivation = allocRootValue(state.allocValue());
|
||||
state.eval(state.parseExprFromString(
|
||||
#include "imported-drv-to-derivation.nix.gen.hh"
|
||||
, CanonPath::root), **state.vImportedDrvToDerivation);
|
||||
, state.rootPath(CanonPath::root)), **state.vImportedDrvToDerivation);
|
||||
}
|
||||
|
||||
state.forceFunction(**state.vImportedDrvToDerivation, pos, "while evaluating imported-drv-to-derivation.nix.gen.hh");
|
||||
|
@ -213,7 +213,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
|||
else if (path2 == corepkgsPrefix + "fetchurl.nix") {
|
||||
state.eval(state.parseExprFromString(
|
||||
#include "fetchurl.nix.gen.hh"
|
||||
, CanonPath::root), v);
|
||||
, state.rootPath(CanonPath::root)), v);
|
||||
}
|
||||
|
||||
else {
|
||||
|
@ -599,7 +599,8 @@ struct CompareValues
|
|||
case nString:
|
||||
return v1->string_view().compare(v2->string_view()) < 0;
|
||||
case nPath:
|
||||
return strcmp(v1->_path, v2->_path) < 0;
|
||||
// FIXME: handle accessor?
|
||||
return strcmp(v1->_path.path, v2->_path.path) < 0;
|
||||
case nList:
|
||||
// Lexicographic comparison
|
||||
for (size_t i = 0;; i++) {
|
||||
|
@ -2203,7 +2204,7 @@ static void addPath(
|
|||
|
||||
path = evalSettings.pureEval && expectedHash
|
||||
? path
|
||||
: state.checkSourcePath(CanonPath(path)).path.abs();
|
||||
: state.checkSourcePath(state.rootPath(CanonPath(path))).path.abs();
|
||||
|
||||
PathFilter filter = filterFun ? ([&](const Path & path) {
|
||||
auto st = lstat(path);
|
||||
|
@ -2236,9 +2237,10 @@ static void addPath(
|
|||
});
|
||||
|
||||
if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) {
|
||||
StorePath dstPath = settings.readOnlyMode
|
||||
? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first
|
||||
: state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs);
|
||||
// FIXME
|
||||
if (method != FileIngestionMethod::Recursive)
|
||||
throw Error("'recursive = false' is not implemented");
|
||||
auto dstPath = state.rootPath(CanonPath(path)).fetchToStore(state.store, name, &filter, state.repair);
|
||||
if (expectedHash && expectedStorePath != dstPath)
|
||||
state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path));
|
||||
state.allowAndSetStorePathString(dstPath, v);
|
||||
|
@ -4447,7 +4449,7 @@ void EvalState::createBaseEnv()
|
|||
// the parser needs two NUL bytes as terminators; one of them
|
||||
// is implied by being a C string.
|
||||
"\0";
|
||||
eval(parse(code, sizeof(code), derivationInternal, {CanonPath::root}, staticBaseEnv), *vDerivation);
|
||||
eval(parse(code, sizeof(code), derivationInternal, rootPath(CanonPath::root), staticBaseEnv), *vDerivation);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace nix {
|
|||
// not supported by store 'dummy'" thrown in the test body.
|
||||
TEST_F(JSONValueTest, DISABLED_Path) {
|
||||
Value v;
|
||||
v.mkPath("test");
|
||||
v.mkPath(state.rootPath(CanonPath("/test")));
|
||||
ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\"");
|
||||
}
|
||||
} /* namespace nix */
|
||||
|
|
|
@ -103,14 +103,17 @@ namespace nix {
|
|||
}
|
||||
|
||||
MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p)) {
|
||||
if (arg.type() != nPath) {
|
||||
*result_listener << "Expected a path got " << arg.type();
|
||||
return false;
|
||||
} else if (std::string_view(arg._path) != p) {
|
||||
*result_listener << "Expected a path that equals \"" << p << "\" but got: " << arg.c_str();
|
||||
if (arg.type() != nPath) {
|
||||
*result_listener << "Expected a path got " << arg.type();
|
||||
return false;
|
||||
} else {
|
||||
auto path = arg.path();
|
||||
if (path.path != CanonPath(p)) {
|
||||
*result_listener << "Expected a path that equals \"" << p << "\" but got: " << path.path;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -189,7 +189,12 @@ public:
|
|||
const char * c_str;
|
||||
const char * * context; // must be in sorted order
|
||||
} string;
|
||||
const char * _path;
|
||||
|
||||
struct {
|
||||
InputAccessor * accessor;
|
||||
const char * path;
|
||||
} _path;
|
||||
|
||||
Bindings * attrs;
|
||||
struct {
|
||||
size_t size;
|
||||
|
@ -286,11 +291,12 @@ public:
|
|||
|
||||
void mkPath(const SourcePath & path);
|
||||
|
||||
inline void mkPath(const char * path)
|
||||
inline void mkPath(InputAccessor * accessor, const char * path)
|
||||
{
|
||||
clearValue();
|
||||
internalType = tPath;
|
||||
_path = path;
|
||||
_path.accessor = accessor;
|
||||
_path.path = path;
|
||||
}
|
||||
|
||||
inline void mkNull()
|
||||
|
@ -437,7 +443,10 @@ public:
|
|||
SourcePath path() const
|
||||
{
|
||||
assert(internalType == tPath);
|
||||
return SourcePath{CanonPath(_path)};
|
||||
return SourcePath {
|
||||
.accessor = ref(_path.accessor->shared_from_this()),
|
||||
.path = CanonPath(CanonPath::unchecked_t(), _path.path)
|
||||
};
|
||||
}
|
||||
|
||||
std::string_view string_view() const
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue