about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc12
-rw-r--r--src/libexpr/primops.cc34
-rw-r--r--src/libstore/build.cc9
-rw-r--r--src/libstore/store-api.hh2
-rw-r--r--src/nix/progress-bar.cc7
-rw-r--r--tests/nix-copy-closure.nix2
-rw-r--r--tests/restricted.sh2
7 files changed, 53 insertions, 15 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 33a9bc614285..7775cbe53cc4 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -378,6 +378,18 @@ void EvalState::checkURI(const std::string & uri)
             && (prefix[prefix.size() - 1] == '/' || uri[prefix.size()] == '/')))
             return;
 
+    /* If the URI is a path, then check it against allowedPaths as
+       well. */
+    if (hasPrefix(uri, "/")) {
+        checkSourcePath(uri);
+        return;
+    }
+
+    if (hasPrefix(uri, "file://")) {
+        checkSourcePath(std::string(uri, 7));
+        return;
+    }
+
     throw RestrictedPathError("access to URI '%s' is forbidden in restricted mode", uri);
 }
 
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 975f0e8309e6..5fe7da216439 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -49,24 +49,38 @@ InvalidPathError::InvalidPathError(const Path & path) :
 void EvalState::realiseContext(const PathSet & context)
 {
     PathSet drvs;
+
     for (auto & i : context) {
         std::pair<string, string> decoded = decodeContext(i);
         Path ctx = decoded.first;
         assert(store->isStorePath(ctx));
         if (!store->isValidPath(ctx))
             throw InvalidPathError(ctx);
-        if (!decoded.second.empty() && nix::isDerivation(ctx))
+        if (!decoded.second.empty() && nix::isDerivation(ctx)) {
             drvs.insert(decoded.first + "!" + decoded.second);
+
+            /* Add the output of this derivation to the allowed
+               paths. */
+            if (allowedPaths) {
+                auto drv = store->derivationFromPath(decoded.first);
+                DerivationOutputs::iterator i = drv.outputs.find(decoded.second);
+                if (i == drv.outputs.end())
+                    throw Error("derivation '%s' does not have an output named '%s'", decoded.first, decoded.second);
+                allowedPaths->insert(i->second.path);
+            }
+        }
     }
-    if (!drvs.empty()) {
-        if (!settings.enableImportFromDerivation)
-            throw EvalError(format("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false") % *(drvs.begin()));
-        /* For performance, prefetch all substitute info. */
-        PathSet willBuild, willSubstitute, unknown;
-        unsigned long long downloadSize, narSize;
-        store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
-        store->buildPaths(drvs);
-    }
+
+    if (drvs.empty()) return;
+
+    if (!settings.enableImportFromDerivation)
+        throw EvalError(format("attempted to realize '%1%' during evaluation but 'allow-import-from-derivation' is false") % *(drvs.begin()));
+
+    /* For performance, prefetch all substitute info. */
+    PathSet willBuild, willSubstitute, unknown;
+    unsigned long long downloadSize, narSize;
+    store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
+    store->buildPaths(drvs);
 }
 
 
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index d4b93b5104c1..5be7ce60dab9 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -3670,7 +3670,7 @@ void SubstitutionGoal::tryNext()
     /* Update the total expected download size. */
     auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);
 
-    maintainExpectedNar = std::make_unique<MaintainCount<uint64_t>>(worker.expectedNarSize, narInfo->narSize);
+    maintainExpectedNar = std::make_unique<MaintainCount<uint64_t>>(worker.expectedNarSize, info->narSize);
 
     maintainExpectedDownload =
         narInfo && narInfo->fileSize
@@ -3684,7 +3684,10 @@ void SubstitutionGoal::tryNext()
     /* Bail out early if this substituter lacks a valid
        signature. LocalStore::addToStore() also checks for this, but
        only after we've downloaded the path. */
-    if (worker.store.requireSigs && !info->checkSignatures(worker.store, worker.store.publicKeys)) {
+    if (worker.store.requireSigs
+        && !sub->isTrusted
+        && !info->checkSignatures(worker.store, worker.store.publicKeys))
+    {
         printInfo(format("warning: substituter '%s' does not have a valid signature for path '%s'")
             % sub->getUri() % storePath);
         tryNext();
@@ -3752,7 +3755,7 @@ void SubstitutionGoal::tryToRun()
             PushActivity pact(act.id);
 
             copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()),
-                storePath, repair);
+                storePath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs);
 
             promise.set_value();
         } catch (...) {
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 70f23e1fcaf4..aa83c2ded8c8 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -248,6 +248,8 @@ public:
 
     const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"};
 
+    const Setting<bool> isTrusted{this, false, "trusted", "whether paths from this store can be used as substitutes even when they lack trusted signatures"};
+
 protected:
 
     struct State
diff --git a/src/nix/progress-bar.cc b/src/nix/progress-bar.cc
index fb9955190b40..8bffda54a551 100644
--- a/src/nix/progress-bar.cc
+++ b/src/nix/progress-bar.cc
@@ -167,7 +167,12 @@ public:
 
         if (type == actSubstitute) {
             auto name = storePathToName(getS(fields, 0));
-            i->s = fmt("fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s", name, getS(fields, 1));
+            auto sub = getS(fields, 1);
+            i->s = fmt(
+                hasPrefix(sub, "local")
+                ? "copying " ANSI_BOLD "%s" ANSI_NORMAL " from %s"
+                : "fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s",
+                name, sub);
         }
 
         if (type == actQueryPathInfo) {
diff --git a/tests/nix-copy-closure.nix b/tests/nix-copy-closure.nix
index 0bf5b42d84a8..be0a4a683cda 100644
--- a/tests/nix-copy-closure.nix
+++ b/tests/nix-copy-closure.nix
@@ -2,7 +2,7 @@
 
 { nixpkgs, system, nix }:
 
-with import (nixpkgs + /nixos/lib/testing.nix) { inherit system; };
+with import (nixpkgs + "/nixos/lib/testing.nix") { inherit system; };
 
 makeTest (let pkgA = pkgs.cowsay; pkgB = pkgs.wget; pkgC = pkgs.hello; in {
 
diff --git a/tests/restricted.sh b/tests/restricted.sh
index 6c0392facf31..0605383cc86a 100644
--- a/tests/restricted.sh
+++ b/tests/restricted.sh
@@ -36,3 +36,5 @@ ln -sfn $(pwd)/restricted.nix $TEST_ROOT/restricted.nix
 (! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I $TEST_ROOT)
 (! nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I .)
 nix-instantiate --eval --restrict-eval $TEST_ROOT/restricted.nix -I $TEST_ROOT -I .
+
+[[ $(nix eval --raw --restrict-eval -I . '(builtins.readFile "${import ./simple.nix}/hello")') == 'Hello World!' ]]