mirror of
https://github.com/NixOS/nix.git
synced 2025-11-26 20:20:58 +01:00
Nix now includes the username into the hash calculation, statepaths are also recomputed at buildtime so they cannot be spoofed
This commit is contained in:
parent
267ccc589d
commit
95ce7e04b7
12 changed files with 111 additions and 39 deletions
|
|
@ -1371,9 +1371,9 @@ void DerivationGoal::startBuilder()
|
|||
env["NIX_STORE"] = nixStore;
|
||||
|
||||
/* Add all bindings specified in the derivation. */
|
||||
for (StringPairs::iterator i = drv.env.begin();
|
||||
i != drv.env.end(); ++i)
|
||||
env[i->first] = i->second;
|
||||
for (StringPairs::iterator i = drv.env.begin(); i != drv.env.end(); ++i){
|
||||
env[i->first] = i->second;
|
||||
}
|
||||
|
||||
/* Create a temporary directory where the build will take
|
||||
place. */
|
||||
|
|
@ -1382,9 +1382,14 @@ void DerivationGoal::startBuilder()
|
|||
/* Create the state directory where the component can store it's state files place */
|
||||
//TODO MOVEEEEEEEEEEE
|
||||
//We only create state dirs when state is enabled and when the dirs need to be created before the installation
|
||||
if(drv.stateOutputs.size() != 0)
|
||||
if(drv.stateOutputs.size() != 0){
|
||||
|
||||
/* we check the recalculated state path at build time with the correct user for securiyt */
|
||||
checkStatePath(drv);
|
||||
|
||||
if(drv.stateOutputs.find("state")->second.getCreateDirsBeforeInstall())
|
||||
createStateDirs(drv.stateOutputDirs, drv.stateOutputs, drv.env);
|
||||
}
|
||||
|
||||
/* For convenience, set an environment pointing to the top build
|
||||
directory. */
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Derive | ATermList ATermList ATermList ATermList ATermList string string ATermLi
|
|||
| string string | ATerm | EnvBinding |
|
||||
| string ATermList | ATerm | DerivationInput |
|
||||
| string string string string | ATerm | DerivationOutput |
|
||||
| string string string string string string string string string string | ATerm | DerivationStateOutput |
|
||||
| string string string string string string string string string string string string | ATerm | DerivationStateOutput |
|
||||
| string string string | ATerm | DerivationStateOutputDir |
|
||||
|
||||
#We use DeriveWithOutState to create derivations that dont use state, and thus dont have the stateDerivationStateOutput and DerivationStateOutputDir in their derivation
|
||||
|
|
|
|||
|
|
@ -92,11 +92,12 @@ Derivation parseDerivation(ATerm t)
|
|||
if(withState){
|
||||
//parse state part
|
||||
for (ATermIterator i(stateOuts); i; ++i) {
|
||||
ATerm id, statepath, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters;
|
||||
if (!matchDerivationStateOutput(*i, id, statepath, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters))
|
||||
ATerm id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters, username;
|
||||
if (!matchDerivationStateOutput(*i, id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters, username))
|
||||
throwBadDrv(t);
|
||||
DerivationStateOutput stateOut;
|
||||
stateOut.statepath = aterm2String(statepath);
|
||||
stateOut.componentHash = aterm2String(componentHash);
|
||||
//checkPath(stateOut.path); //should we check the statpath .... ???
|
||||
stateOut.hashAlgo = aterm2String(hashAlgo);
|
||||
stateOut.hash = aterm2String(hash);
|
||||
|
|
@ -106,6 +107,7 @@ Derivation parseDerivation(ATerm t)
|
|||
stateOut.synchronization = aterm2String(synchronization);
|
||||
stateOut.createDirsBeforeInstall = aterm2String(createDirsBeforeInstall);
|
||||
stateOut.runtimeStateParamters = aterm2String(runtimeStateParamters);
|
||||
stateOut.username = aterm2String(username);
|
||||
drv.stateOutputs[aterm2String(id)] = stateOut;
|
||||
}
|
||||
}
|
||||
|
|
@ -182,6 +184,7 @@ ATerm unparseDerivation(const Derivation & drv)
|
|||
makeDerivationStateOutput(
|
||||
toATerm(i->first),
|
||||
toATerm(i->second.statepath),
|
||||
toATerm(i->second.componentHash),
|
||||
toATerm(i->second.hashAlgo),
|
||||
toATerm(i->second.hash),
|
||||
toATerm(i->second.stateIdentifier),
|
||||
|
|
@ -189,7 +192,8 @@ ATerm unparseDerivation(const Derivation & drv)
|
|||
toATerm(i->second.shared),
|
||||
toATerm(i->second.synchronization),
|
||||
toATerm(i->second.createDirsBeforeInstall),
|
||||
toATerm(i->second.runtimeStateParamters)
|
||||
toATerm(i->second.runtimeStateParamters),
|
||||
toATerm(i->second.username)
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ struct DerivationOutput
|
|||
struct DerivationStateOutput
|
||||
{
|
||||
Path statepath;
|
||||
string componentHash;
|
||||
string hashAlgo;
|
||||
string hash;
|
||||
string stateIdentifier; //the identifier
|
||||
|
|
@ -50,17 +51,21 @@ struct DerivationStateOutput
|
|||
string createDirsBeforeInstall; //if true: creates state dirs before installation
|
||||
string runtimeStateParamters; //if not empty: these are the runtime parameters where state can be found (you can use $statepath here)
|
||||
|
||||
string username;
|
||||
|
||||
DerivationStateOutput()
|
||||
{
|
||||
}
|
||||
|
||||
DerivationStateOutput(Path statepath, string hashAlgo, string hash, string stateIdentifier, string enabled, string shared, string synchronization, string createDirsBeforeInstall, string runtimeStateParamters, bool check=true)
|
||||
DerivationStateOutput(Path statepath, string componentHash, string hashAlgo, string hash, string stateIdentifier, string enabled, string shared, string synchronization, string createDirsBeforeInstall, string runtimeStateParamters, string username, bool check=true)
|
||||
{
|
||||
if(check){
|
||||
if(shared != "none" && shared != "full" && shared != "group")
|
||||
throw Error(format("shared '%1%' is not a correct type") % shared);
|
||||
if(synchronization != "none" && synchronization != "exclusive-lock" && synchronization != "recursive-exclusive-lock")
|
||||
throw Error(format("synchronization '%1%' is not a correct type") % synchronization);
|
||||
if(username == "")
|
||||
throw Error(format("Username cannot be empty"));
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
|
@ -68,6 +73,7 @@ struct DerivationStateOutput
|
|||
//commitBinaries
|
||||
|
||||
this->statepath = statepath;
|
||||
this->componentHash = componentHash;
|
||||
this->hashAlgo = hashAlgo;
|
||||
this->hash = hash;
|
||||
this->stateIdentifier = stateIdentifier;
|
||||
|
|
@ -76,6 +82,7 @@ struct DerivationStateOutput
|
|||
this->synchronization = synchronization;
|
||||
this->createDirsBeforeInstall = createDirsBeforeInstall;
|
||||
this->runtimeStateParamters = runtimeStateParamters;
|
||||
this->username = username;
|
||||
}
|
||||
|
||||
bool getEnabled(){
|
||||
|
|
@ -91,14 +98,16 @@ struct DerivationStateOutput
|
|||
*/
|
||||
void clearAllRuntimeParamters(){
|
||||
this->statepath = "";
|
||||
this->componentHash = "";
|
||||
//this->hashAlgo; //Clear this one?
|
||||
//this->hash; //Clear this one?
|
||||
//this->stateIdentifier;
|
||||
//this->stateIdentifier; //Changes the statepath directly
|
||||
this->enabled = "";
|
||||
this->shared = "";
|
||||
this->synchronization = "";
|
||||
this->createDirsBeforeInstall = "";
|
||||
this->runtimeStateParamters = "";
|
||||
//this->username; //Changes the statepath directly
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -421,6 +421,7 @@ Path queryDeriver(const Transaction & txn, const Path & storePath)
|
|||
if (!isRealisablePath(txn, storePath))
|
||||
throw Error(format("path `%1%' is not valid") % storePath);
|
||||
Path deriver;
|
||||
|
||||
if (nixDB.queryString(txn, dbDerivers, storePath, deriver))
|
||||
return deriver;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -79,24 +79,44 @@ Path makeStorePath(const string & type, const Hash & hash, const string & suffix
|
|||
+ "-" + suffix;
|
||||
}
|
||||
|
||||
Path makeStatePath(const string & type, const Hash & hash, const string & suffix, const string & stateIdentifier)
|
||||
Path makeStatePath(const string & componentHash, const string & suffix, const string & stateIdentifier)
|
||||
{
|
||||
string suffix_stateIdentifier = stateIdentifier;
|
||||
if(suffix_stateIdentifier != "")
|
||||
suffix_stateIdentifier = "-" + suffix_stateIdentifier;
|
||||
|
||||
string username = getCallingUserName(); //Can and Should NOT be faked
|
||||
|
||||
/* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
|
||||
string s = type + ":sha256:" + printHash(hash) + ":"
|
||||
+ nixStoreState + ":" + suffix + ":" + stateIdentifier;
|
||||
string s = ":sha256:" + componentHash + ":"
|
||||
+ nixStoreState + ":" + suffix + ":" + stateIdentifier + ":" + username;
|
||||
|
||||
checkStoreName(suffix);
|
||||
checkStoreName(stateIdentifier);
|
||||
|
||||
return nixStoreState + "/"
|
||||
+ printHash32(compressHash(hashString(htSHA256, s), 20))
|
||||
+ "-" + suffix + suffix_stateIdentifier;
|
||||
return nixStoreState + "/"
|
||||
+ printHash32(compressHash(hashString(htSHA256, s), 20))
|
||||
+ "-" + suffix + suffix_stateIdentifier;
|
||||
}
|
||||
|
||||
void checkStatePath(const Derivation & drv)
|
||||
{
|
||||
Path drvPath = drv.stateOutputs.find("state")->second.statepath;
|
||||
|
||||
string componentHash = drv.stateOutputs.find("state")->second.componentHash;
|
||||
string suffix = drv.env.find("name")->second;
|
||||
string stateIdentifier = drv.stateOutputs.find("state")->second.stateIdentifier;
|
||||
Path calculatedPath = makeStatePath(componentHash, suffix, stateIdentifier);
|
||||
|
||||
printMsg(lvlError, format("CHECK: %1% %2%") % drvPath % calculatedPath);
|
||||
|
||||
|
||||
if(drvPath != calculatedPath)
|
||||
Error(format("The statepath from the Derivation does not match the recalculated statepath, are u trying to spoof the statepath?"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Path makeStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier)
|
||||
{
|
||||
//This is a little trick: we could use the same hash as the statepath, but we change it so the repository also gets a unique scannable hash
|
||||
|
|
|
|||
|
|
@ -228,8 +228,11 @@ Path makeStorePath(const string & type,
|
|||
Path makeFixedOutputPath(bool recursive,
|
||||
string hashAlgo, Hash hash, string name);
|
||||
|
||||
/* Constructs a unique store state path name. */
|
||||
Path makeStatePath(const string & type, const Hash & hash, const string & suffix, const string & stateIdentifier);
|
||||
/* TODO ... */
|
||||
Path makeStatePath(const string & componentHash, const string & suffix, const string & stateIdentifier);
|
||||
|
||||
/* TODO ... */
|
||||
void checkStatePath(const Derivation & drv);
|
||||
|
||||
/* Constructs a unique store state repos path name. */
|
||||
Path makeStateReposPath(const string & type, const Path statePath, const string subfolder, const string & suffix, const string & stateIdentifier);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue