* 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

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