Make CA derivations compatible with recursive Nix

Add an access-control list to the realisations in recursive-nix (similar
to the already existing one for store paths), so that we can build
content-addressed derivations in the restricted store.

Fix #4353
This commit is contained in:
regnat 2021-06-23 17:27:18 +02:00
parent 0a535dd5ac
commit 7746cb13dc
5 changed files with 48 additions and 10 deletions

View file

@ -1333,13 +1333,18 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
std::optional<const Realisation> queryRealisation(const DrvOutput & id) override std::optional<const Realisation> queryRealisation(const DrvOutput & id) override
// XXX: This should probably be allowed if the realisation corresponds to // XXX: This should probably be allowed if the realisation corresponds to
// an allowed derivation // an allowed derivation
{ throw Error("queryRealisation"); } {
if (!goal.isAllowed(id))
throw InvalidPath("cannot query an unknown output id '%s' in recursive Nix", id.to_string());
return next->queryRealisation(id);
}
void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode) override void buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode) override
{ {
if (buildMode != bmNormal) throw Error("unsupported build mode"); if (buildMode != bmNormal) throw Error("unsupported build mode");
StorePathSet newPaths; StorePathSet newPaths;
std::set<Realisation> newRealisations;
for (auto & req : paths) { for (auto & req : paths) {
if (!goal.isAllowed(req)) if (!goal.isAllowed(req))
@ -1352,16 +1357,28 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
auto p = std::get_if<DerivedPath::Built>(&path); auto p = std::get_if<DerivedPath::Built>(&path);
if (!p) continue; if (!p) continue;
auto & bfd = *p; auto & bfd = *p;
auto drv = readDerivation(bfd.drvPath);
auto drvHashes = staticOutputHashes(*this, drv);
auto outputs = next->queryDerivationOutputMap(bfd.drvPath); auto outputs = next->queryDerivationOutputMap(bfd.drvPath);
for (auto & [outputName, outputPath] : outputs) for (auto & [outputName, outputPath] : outputs)
if (wantOutput(outputName, bfd.outputs)) if (wantOutput(outputName, bfd.outputs)) {
newPaths.insert(outputPath); newPaths.insert(outputPath);
if (settings.isExperimentalFeatureEnabled("ca-derivations")) {
auto thisRealisation = next->queryRealisation(
DrvOutput{drvHashes.at(outputName), outputName}
);
assert(thisRealisation);
newRealisations.insert(*thisRealisation);
}
}
} }
StorePathSet closure; StorePathSet closure;
next->computeFSClosure(newPaths, closure); next->computeFSClosure(newPaths, closure);
for (auto & path : closure) for (auto & path : closure)
goal.addDependency(path); goal.addDependency(path);
for (auto & real : Realisation::closure(*next, newRealisations))
goal.addedDrvOutputs.insert(real.id);
} }
BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,

View file

@ -108,6 +108,9 @@ struct LocalDerivationGoal : public DerivationGoal
/* Paths that were added via recursive Nix calls. */ /* Paths that were added via recursive Nix calls. */
StorePathSet addedPaths; StorePathSet addedPaths;
/* Realisations that were added via recursive Nix calls. */
std::set<DrvOutput> addedDrvOutputs;
/* Recursive Nix calls are only allowed to build or realize paths /* Recursive Nix calls are only allowed to build or realize paths
in the original input closure or added via a recursive Nix call in the original input closure or added via a recursive Nix call
(so e.g. you can't do 'nix-store -r /nix/store/<bla>' where (so e.g. you can't do 'nix-store -r /nix/store/<bla>' where
@ -116,6 +119,11 @@ struct LocalDerivationGoal : public DerivationGoal
{ {
return inputPaths.count(path) || addedPaths.count(path); return inputPaths.count(path) || addedPaths.count(path);
} }
bool isAllowed(const DrvOutput & id)
{
return addedDrvOutputs.count(id);
}
bool isAllowed(const DerivedPath & req); bool isAllowed(const DerivedPath & req);
friend struct RestrictedStore; friend struct RestrictedStore;

11
tests/ca/recursive.sh Executable file
View file

@ -0,0 +1,11 @@
#!/usr/bin/env bash
source common.sh
sed -i 's/experimental-features .*/& ca-derivations ca-references nix-command flakes/' "$NIX_CONF_DIR"/nix.conf
export NIX_TESTS_CA_BY_DEFAULT=1
cd ..
source ./recursive.sh

View file

@ -52,6 +52,7 @@ nix_tests = \
ca/signatures.sh \ ca/signatures.sh \
ca/nix-shell.sh \ ca/nix-shell.sh \
ca/nix-run.sh \ ca/nix-run.sh \
ca/recursive.sh \
ca/nix-copy.sh ca/nix-copy.sh
# parallel.sh # parallel.sh

View file

@ -9,9 +9,9 @@ rm -f $TEST_ROOT/result
export unreachable=$(nix store add-path ./recursive.sh) export unreachable=$(nix store add-path ./recursive.sh)
NIX_BIN_DIR=$(dirname $(type -p nix)) nix --experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L --impure --expr ' NIX_BIN_DIR=$(dirname $(type -p nix)) nix --extra-experimental-features 'nix-command recursive-nix' build -o $TEST_ROOT/result -L --impure --expr '
with import ./config.nix; with import ./config.nix;
mkDerivation { mkDerivation rec {
name = "recursive"; name = "recursive";
dummy = builtins.toFile "dummy" "bla bla"; dummy = builtins.toFile "dummy" "bla bla";
SHELL = shell; SHELL = shell;
@ -19,11 +19,13 @@ NIX_BIN_DIR=$(dirname $(type -p nix)) nix --experimental-features 'nix-command r
# Note: this is a string without context. # Note: this is a string without context.
unreachable = builtins.getEnv "unreachable"; unreachable = builtins.getEnv "unreachable";
NIX_TESTS_CA_BY_DEFAULT = builtins.getEnv "NIX_TESTS_CA_BY_DEFAULT";
requiredSystemFeatures = [ "recursive-nix" ]; requiredSystemFeatures = [ "recursive-nix" ];
buildCommand = '\'\'' buildCommand = '\'\''
mkdir $out mkdir $out
opts="--experimental-features nix-command" opts="--experimental-features nix-command ${if (NIX_TESTS_CA_BY_DEFAULT == "1") then "--extra-experimental-features ca-derivations" else ""}"
PATH=${builtins.getEnv "NIX_BIN_DIR"}:$PATH PATH=${builtins.getEnv "NIX_BIN_DIR"}:$PATH
@ -46,16 +48,15 @@ NIX_BIN_DIR=$(dirname $(type -p nix)) nix --experimental-features 'nix-command r
# Add it to our closure. # Add it to our closure.
ln -s $foobar $out/foobar ln -s $foobar $out/foobar
[[ $(nix $opts path-info --all | wc -l) -eq 3 ]] [[ $(nix $opts path-info --all | wc -l) -eq 4 ]]
# Build a derivation. # Build a derivation.
nix $opts build -L --impure --expr '\'' nix $opts build -L --impure --expr '\''
derivation { with import ${./config.nix};
mkDerivation {
name = "inner1"; name = "inner1";
builder = builtins.getEnv "SHELL"; buildCommand = "echo $fnord blaat > $out";
system = builtins.getEnv "system";
fnord = builtins.toFile "fnord" "fnord"; fnord = builtins.toFile "fnord" "fnord";
args = [ "-c" "echo $fnord blaat > $out" ];
} }
'\'' '\''