* Don't allow derivations with fixed and non-fixed outputs.

This commit is contained in:
Eelco Dolstra 2011-07-20 18:26:00 +00:00
parent b2027f70d9
commit c8606664ab
1 changed files with 40 additions and 45 deletions

View File

@ -394,53 +394,48 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
throw EvalError(format("derivation names are not allowed to end in `%1%'")
% drvExtension);
/* Construct the "masked" store derivation, which is the final one
except that in the list of outputs, the output paths are empty,
and the corresponding environment variables have an empty
value. This ensures that changes in the set of output names do
get reflected in the hash.
However, for fixed-output derivations, we can compute the
output path directly, so we don't need this. */
bool fixedOnly = true;
foreach (StringSet::iterator, i, outputs) {
if (*i != "out" || outputHash == "") {
drv.env[*i] = "";
drv.outputs[*i] = DerivationOutput("", "", "");
fixedOnly = false;
} else {
/* If an output hash was given, check it, and compute the
output path. */
HashType ht = parseHashType(outputHashAlgo);
if (ht == htUnknown)
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
Hash h(ht);
if (outputHash.size() == h.hashSize * 2)
/* hexadecimal representation */
h = parseHash(ht, outputHash);
else if (outputHash.size() == hashLength32(h))
/* base-32 representation */
h = parseHash32(ht, outputHash);
else
throw Error(format("hash `%1%' has wrong length for hash type `%2%'")
% outputHash % outputHashAlgo);
string s = outputHash;
outputHash = printHash(h);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
drv.env[*i] = outPath;
drv.outputs[*i] = DerivationOutput(outPath, outputHashAlgo, outputHash);
}
if (outputHash != "") {
/* Handle fixed-output derivations. */
if (outputs.size() != 1 || *(outputs.begin()) != "out")
throw Error("multiple outputs are not supported in fixed-output derivations");
HashType ht = parseHashType(outputHashAlgo);
if (ht == htUnknown)
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
Hash h(ht);
if (outputHash.size() == h.hashSize * 2)
/* hexadecimal representation */
h = parseHash(ht, outputHash);
else if (outputHash.size() == hashLength32(h))
/* base-32 representation */
h = parseHash32(ht, outputHash);
else
throw Error(format("hash `%1%' has wrong length for hash type `%2%'")
% outputHash % outputHashAlgo);
string s = outputHash;
outputHash = printHash(h);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
drv.env["out"] = outPath;
drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
}
/* Use the masked derivation expression to compute the output
path. !!! Isn't it a potential security problem that the name
of each output path (including the suffix) isn't taken into
account? For instance, changing the suffix for one path
(i->first == "out" ...) doesn't affect the hash of the
others. Is that exploitable? */
if (!fixedOnly) {
else {
/* Construct the "masked" store derivation, which is the final
one except that in the list of outputs, the output paths
are empty, and the corresponding environment variables have
an empty value. This ensures that changes in the set of
output names do get reflected in the hash. */
foreach (StringSet::iterator, i, outputs) {
drv.env[*i] = "";
drv.outputs[*i] = DerivationOutput("", "", "");
}
/* Use the masked derivation expression to compute the output
path. */
Hash h = hashDerivationModulo(drv);
foreach (DerivationOutputs::iterator, i, drv.outputs)
if (i->second.path == "") {
Path outPath = makeOutputPath(i->first, h, drvName);
@ -448,7 +443,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
i->second.path = outPath;
}
}
/* Write the resulting term into the Nix store directory. */
Path drvPath = writeDerivation(drv, drvName);