Skip to content

Commit 5ccd945

Browse files
committed
Allow trustless building of CA derivations
Include a long comment explaining the policy. Perhaps this can be moved to the manual at some point in the future. Also bump the daemon protocol minor version, so clients can tell whether `wopBuildDerivation` supports trustless CA derivation building. I hope to take advantage of this in a follow-up PR to support trustless remote building with the minimal sending of derivation closures.
1 parent d2f2be0 commit 5ccd945

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

src/libstore/daemon.cc

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,46 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
454454
readDerivation(from, *store, drv, Derivation::nameFromPath(drvPath));
455455
BuildMode buildMode = (BuildMode) readInt(from);
456456
logger->startWork();
457-
if (!trusted)
458-
throw Error("you are not privileged to build derivations");
457+
458+
/* Content-addressed derivations are trustless because their output paths
459+
are verified by their content alone, so any derivation is free to
460+
try to produce such a path.
461+
462+
Input-addressed derivation output paths, however, are calculated
463+
from the derivation closure that produced them---even knowing the
464+
root derivation is not enough. That the output data actually came
465+
from those derivations is fundamentally unverifiable, but the daemon
466+
trusts itself on that matter. The question instead is whether the
467+
submitted plan has rights to the output paths it wants to fill, and
468+
at least the derivation closure proves that.
469+
470+
It would have been nice if input-address algorithm merely depended
471+
on the build time closure, rather than depending on the derivation
472+
closure. That would mean input-addressed paths used at build time
473+
would just be trusted and not need their own evidence. This is in
474+
fact fine as the same guarantees would hold *inductively*: either
475+
the remote builder has those paths and already trusts them, or it
476+
needs to build them too and thus their evidence must be provided in
477+
turn. The advantage of this variant algorithm is that the evidence
478+
for input-addressed paths which the remote builder already has
479+
doesn't need to be sent again.
480+
481+
That said, now that we have floating CA derivations, it is better
482+
that people just migrate to those which also solve this problem, and
483+
others. It's the same migration difficulty with strictly more
484+
benefit.
485+
486+
Lastly, do note that when we parse fixed-output content-addressed
487+
derivations, we throw out the precomputed output paths and just
488+
store the hashes, so there aren't two competing sources of truth an
489+
attacker could exploit. */
490+
if (drv.type() == DerivationType::InputAddressed && !trusted)
491+
throw Error("you are not privileged to build input-addressed derivations");
492+
493+
/* Make sure that the non-input-addressed derivations that got this far
494+
are in fact content-addressed if we don't trust them. */
495+
assert(derivationIsCA(drv.type()) || trusted);
496+
459497
auto res = store->buildDerivation(drvPath, drv, buildMode);
460498
logger->stopWork();
461499
to << res.status << res.errorMsg;

src/libstore/worker-protocol.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace nix {
66
#define WORKER_MAGIC_1 0x6e697863
77
#define WORKER_MAGIC_2 0x6478696f
88

9-
#define PROTOCOL_VERSION 0x117
9+
#define PROTOCOL_VERSION 0x118
1010
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
1111
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
1212

0 commit comments

Comments
 (0)