diff options
Diffstat (limited to 'src/libexpr')
-rw-r--r-- | src/libexpr/eval.cc | 20 | ||||
-rw-r--r-- | src/libexpr/eval.hh | 2 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 3 | ||||
-rw-r--r-- | src/libexpr/primops/fetchgit.cc | 7 |
4 files changed, 27 insertions, 5 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 548537b72ced..63de2d60a147 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -355,6 +355,26 @@ Path EvalState::checkSourcePath(const Path & path_) } +void EvalState::checkURI(const std::string & uri) +{ + if (!restricted) return; + + /* 'uri' should be equal to a prefix, or in a subdirectory of a + prefix. Thus, the prefix https://github.co does not permit + access to https://github.com. Note: this allows 'http://' and + 'https://' as prefixes for any http/https URI. */ + for (auto & prefix : settings.allowedUris.get()) + if (uri == prefix || + (uri.size() > prefix.size() + && prefix.size() > 0 + && hasPrefix(uri, prefix) + && (prefix[prefix.size() - 1] == '/' || uri[prefix.size()] == '/'))) + return; + + throw RestrictedPathError("access to URI '%s' is forbidden in restricted mode", uri); +} + + void EvalState::addConstant(const string & name, Value & v) { Value * v2 = allocValue(); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 04a36b14cefa..f0ab1435bff3 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -110,6 +110,8 @@ public: Path checkSourcePath(const Path & path); + void checkURI(const std::string & uri); + /* Parse a Nix expression from the specified file. */ Expr * parseExprFromFile(const Path & path); Expr * parseExprFromFile(const Path & path, StaticEnv & staticEnv); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 22925ba4de19..cd0dfbc03e94 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1937,8 +1937,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, } else url = state.forceStringNoCtx(*args[0], pos); - if (state.restricted) - throw Error(format("'%1%' is not allowed in restricted mode") % who); + state.checkURI(url); Path res = getDownloader()->downloadCached(state.store, url, unpack, name, expectedHash); mkString(v, res, PathSet({res})); diff --git a/src/libexpr/primops/fetchgit.cc b/src/libexpr/primops/fetchgit.cc index 38bffd8dbdbc..81b641900593 100644 --- a/src/libexpr/primops/fetchgit.cc +++ b/src/libexpr/primops/fetchgit.cc @@ -113,9 +113,6 @@ GitInfo exportGit(ref<Store> store, const std::string & uri, static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Value & v) { - // FIXME: cut&paste from fetch(). - if (state.restricted) throw Error("'fetchGit' is not allowed in restricted mode"); - std::string url; std::string ref = "master"; std::string rev; @@ -150,6 +147,10 @@ static void prim_fetchGit(EvalState & state, const Pos & pos, Value * * args, Va } else url = state.forceStringNoCtx(*args[0], pos); + // FIXME: git externals probably can be used to bypass the URI + // whitelist. Ah well. + state.checkURI(url); + auto gitInfo = exportGit(state.store, url, ref, rev, name); state.mkAttrs(v, 8); |