about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-10-30T11·39+0100
committerEelco Dolstra <edolstra@gmail.com>2017-10-30T11·41+0100
commit812e027e1d5a4f83394069edd67bdf8404ffa2bb (patch)
treefe11aee398ea3ddfa0a8117c566e2ed1c6435883 /src
parentf1c555cef870654cdaf232b5d08fdbba0bf06add (diff)
Add option allowed-uris
This allows network access in restricted eval mode.
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval.cc20
-rw-r--r--src/libexpr/eval.hh2
-rw-r--r--src/libexpr/primops.cc3
-rw-r--r--src/libexpr/primops/fetchgit.cc7
-rw-r--r--src/libstore/globals.hh4
5 files changed, 30 insertions, 6 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);
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 538273b546be..a4aa842d70fd 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -225,7 +225,7 @@ public:
 
     Setting<bool> restrictEval{this, false, "restrict-eval",
         "Whether to restrict file system access to paths in $NIX_PATH, "
-        "and to disallow fetching files from the network."};
+        "and network access to the URI prefixes listed in 'allowed-uris'."};
 
     Setting<size_t> buildRepeat{this, 0, "repeat",
         "The number of times to repeat a build in order to verify determinism.",
@@ -353,6 +353,8 @@ public:
     Setting<uint64_t> maxFree{this, std::numeric_limits<uint64_t>::max(), "max-free",
         "Stop deleting garbage when free disk space is above the specified amount."};
 
+    Setting<Strings> allowedUris{this, {}, "allowed-uris",
+        "Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."};
 };