* Renamed normalise.cc' -> build.cc', `storeexprs.cc' ->
				
					
				
			`derivations.cc', etc. * Store the SHA-256 content hash of store paths in the database after they have been built/added. This is so that we can check whether the store has been messed with (a la `rpm --verify'). * When registering path validity, verify that the closure property holds.
This commit is contained in:
		
							parent
							
								
									ef5f254a55
								
							
						
					
					
						commit
						96de272b48
					
				
					 19 changed files with 128 additions and 98 deletions
				
			
		|  | @ -1,5 +1,5 @@ | |||
| #include "nixexpr.hh" | ||||
| #include "storeexpr.hh" | ||||
| #include "derivations.hh" | ||||
| 
 | ||||
| 
 | ||||
| #include "nixexpr-ast.hh" | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| #include "normalise.hh" | ||||
| #include "build.hh" | ||||
| #include "eval.hh" | ||||
| #include "globals.hh" | ||||
| #include "nixexpr-ast.hh" | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ void checkStoreNotSymlink(Path path) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void initStoreExprHelpers(); | ||||
| void initDerivationsHelpers(); | ||||
| 
 | ||||
| 
 | ||||
| /* Initialize and reorder arguments, then call the actual argument
 | ||||
|  | @ -105,7 +105,7 @@ static void initAndRun(int argc, char * * argv) | |||
|     if (lt != "") setLogType(lt); | ||||
| 
 | ||||
|     /* ATerm stuff.  !!! find a better place to put this */ | ||||
|     initStoreExprHelpers(); | ||||
|     initDerivationsHelpers(); | ||||
|      | ||||
|     /* Put the arguments in a vector. */ | ||||
|     Strings args, remaining; | ||||
|  |  | |||
|  | @ -1,18 +1,18 @@ | |||
| noinst_LIBRARIES = libstore.a | ||||
| 
 | ||||
| libstore_a_SOURCES = \ | ||||
|  store.cc store.hh storeexpr.cc storeexpr.hh \ | ||||
|  normalise.cc misc.cc normalise.hh \ | ||||
|  store.cc store.hh derivations.cc derivations.hh \ | ||||
|  build.cc misc.cc build.hh \ | ||||
|  globals.cc globals.hh db.cc db.hh \ | ||||
|  references.cc references.hh pathlocks.cc pathlocks.hh \ | ||||
|  gc.cc gc.hh storeexpr-ast.hh | ||||
|  gc.cc gc.hh derivations-ast.hh | ||||
| 
 | ||||
| EXTRA_DIST = storeexpr-ast.def storeexpr-ast.cc | ||||
| EXTRA_DIST = derivations-ast.def derivations-ast.cc | ||||
| 
 | ||||
| AM_CXXFLAGS = -Wall \ | ||||
|  -I.. ${bdb_include} ${aterm_include} -I../libutil | ||||
| 
 | ||||
| storeexpr-ast.cc storeexpr-ast.hh: ../aterm-helper.pl storeexpr-ast.def | ||||
| 	$(perl) ../aterm-helper.pl storeexpr-ast.hh storeexpr-ast.cc < storeexpr-ast.def | ||||
| derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def | ||||
| 	$(perl) ../aterm-helper.pl derivations-ast.hh derivations-ast.cc < derivations-ast.def | ||||
| 
 | ||||
| storeexpr.cc: storeexpr-ast.hh | ||||
| derivations.cc: derivations-ast.hh | ||||
|  | @ -5,13 +5,11 @@ | |||
| 
 | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/time.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <utime.h> | ||||
| 
 | ||||
| #include "normalise.hh" | ||||
| #include "build.hh" | ||||
| #include "references.hh" | ||||
| #include "pathlocks.hh" | ||||
| #include "globals.hh" | ||||
|  | @ -285,60 +283,6 @@ const char * * strings2CharPtrs(const Strings & ss) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* "Fix", or canonicalise, the meta-data of the files in a store path
 | ||||
|    after it has been built.  In particular: | ||||
|    - the last modification date on each file is set to 0 (i.e., | ||||
|      00:00:00 1/1/1970 UTC) | ||||
|    - the permissions are set of 444 or 555 (i.e., read-only with or | ||||
|      without execute permission; setuid bits etc. are cleared) | ||||
|    - the owner and group are set to the Nix user and group, if we're | ||||
|      in a setuid Nix installation | ||||
| */ | ||||
| void canonicalisePathMetaData(const Path & path) | ||||
| { | ||||
|     checkInterrupt(); | ||||
| 
 | ||||
|     struct stat st; | ||||
|     if (lstat(path.c_str(), &st)) | ||||
| 	throw SysError(format("getting attributes of path `%1%'") % path); | ||||
| 
 | ||||
|     if (!S_ISLNK(st.st_mode)) { | ||||
| 
 | ||||
|         /* Mask out all type related bits. */ | ||||
|         mode_t mode = st.st_mode & ~S_IFMT; | ||||
|          | ||||
|         if (mode != 0444 && mode != 0555) { | ||||
|             mode = (st.st_mode & S_IFMT) | ||||
|                  | 0444 | ||||
|                  | (st.st_mode & S_IXUSR ? 0111 : 0); | ||||
|             if (chmod(path.c_str(), mode) == -1) | ||||
|                 throw SysError(format("changing mode of `%1%' to %2$o") % path % mode); | ||||
|         } | ||||
| 
 | ||||
|         if (st.st_uid != getuid() || st.st_gid != getgid()) { | ||||
|             if (chown(path.c_str(), getuid(), getgid()) == -1) | ||||
|                 throw SysError(format("changing owner/group of `%1%' to %2%/%3%") | ||||
|                     % path % getuid() % getgid()); | ||||
|         } | ||||
| 
 | ||||
|         if (st.st_mtime != 0) { | ||||
|             struct utimbuf utimbuf; | ||||
|             utimbuf.actime = st.st_atime; | ||||
|             utimbuf.modtime = 0; | ||||
|             if (utime(path.c_str(), &utimbuf) == -1)  | ||||
|                 throw SysError(format("changing modification time of `%1%'") % path); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     if (S_ISDIR(st.st_mode)) { | ||||
|         Strings names = readDirectory(path); | ||||
| 	for (Strings::iterator i = names.begin(); i != names.end(); ++i) | ||||
| 	    canonicalisePathMetaData(path + "/" + *i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|  | @ -1041,6 +985,7 @@ void DerivationGoal::computeClosure() | |||
|         format("determining closure for `%1%'") % drvPath); | ||||
| 
 | ||||
|     map<Path, PathSet> allReferences; | ||||
|     map<Path, Hash> contentHashes; | ||||
|      | ||||
|     /* Check whether the output paths were created, and grep each
 | ||||
|        output path to determine what other paths it references.  Also make all | ||||
|  | @ -1109,6 +1054,12 @@ void DerivationGoal::computeClosure() | |||
|         } | ||||
| 
 | ||||
|         allReferences[path] = references; | ||||
| 
 | ||||
|         /* Hash the contents of the path.  The hash is stored in the
 | ||||
|            database so that we can verify later on whether nobody has | ||||
|            messed with the store.  !!! inefficient: it would be nice | ||||
|            if we could combine this with filterReferences(). */ | ||||
|         contentHashes[path] = hashPath(htSHA256, path); | ||||
|     } | ||||
| 
 | ||||
|     /* Register each output path as valid, and register the sets of
 | ||||
|  | @ -1127,7 +1078,8 @@ void DerivationGoal::computeClosure() | |||
|     for (DerivationOutputs::iterator i = drv.outputs.begin();  | ||||
|          i != drv.outputs.end(); ++i) | ||||
|     { | ||||
|         registerValidPath(txn, i->second.path); | ||||
|         registerValidPath(txn, i->second.path, | ||||
|             contentHashes[i->second.path]); | ||||
|         setReferences(txn, i->second.path, | ||||
|             allReferences[i->second.path]); | ||||
|     } | ||||
|  | @ -1460,9 +1412,11 @@ void SubstitutionGoal::finished() | |||
| 
 | ||||
|     canonicalisePathMetaData(storePath); | ||||
| 
 | ||||
|     Hash contentHash = hashPath(htSHA256, storePath); | ||||
| 
 | ||||
|     Transaction txn; | ||||
|     createStoreTransaction(txn); | ||||
|     registerValidPath(txn, storePath); | ||||
|     registerValidPath(txn, storePath, contentHash); | ||||
|     txn.commit(); | ||||
| 
 | ||||
|     outputLock->setDeletion(true); | ||||
|  | @ -1,7 +1,7 @@ | |||
| #ifndef __NORMALISE_H | ||||
| #define __NORMALISE_H | ||||
| #ifndef __BUILD_H | ||||
| #define __BUILD_H | ||||
| 
 | ||||
| #include "storeexpr.hh" | ||||
| #include "derivations.hh" | ||||
| 
 | ||||
| /* Perform the specified derivations, if necessary.  That is, do
 | ||||
|    whatever is necessary to create the output paths of the derivation. | ||||
|  | @ -44,4 +44,4 @@ void computeFSClosure(const Path & storePath, | |||
| void storePathRequisites(const Path & storePath, | ||||
|     bool includeOutputs, PathSet & paths); | ||||
| 
 | ||||
| #endif /* !__NORMALISE_H */ | ||||
| #endif /* !__BUILD_H */ | ||||
|  | @ -1,4 +1,4 @@ | |||
| init initStoreExprHelpers | ||||
| init initDerivationsHelpers | ||||
| 
 | ||||
| Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm | | ||||
| 
 | ||||
|  | @ -1,9 +1,9 @@ | |||
| #include "storeexpr.hh" | ||||
| #include "derivations.hh" | ||||
| #include "globals.hh" | ||||
| #include "store.hh" | ||||
| 
 | ||||
| #include "storeexpr-ast.hh" | ||||
| #include "storeexpr-ast.cc" | ||||
| #include "derivations-ast.hh" | ||||
| #include "derivations-ast.cc" | ||||
| 
 | ||||
| 
 | ||||
| Hash hashTerm(ATerm t) | ||||
|  | @ -1,5 +1,5 @@ | |||
| #ifndef __STOREEXPR_H | ||||
| #define __STOREEXPR_H | ||||
| #ifndef __DERIVATIONS_H | ||||
| #define __DERIVATIONS_H | ||||
| 
 | ||||
| #include "aterm.hh" | ||||
| #include "store.hh" | ||||
|  | @ -59,4 +59,4 @@ ATerm unparseDerivation(const Derivation & drv); | |||
| bool isDerivation(const string & fileName); | ||||
| 
 | ||||
| 
 | ||||
| #endif /* !__STOREEXPR_H */ | ||||
| #endif /* !__DERIVATIONS_H */ | ||||
|  | @ -1,5 +1,5 @@ | |||
| #include "normalise.hh" | ||||
| #include "globals.hh" | ||||
| #include "gc.hh" | ||||
| 
 | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #ifndef __GC_H | ||||
| #define __GC_H | ||||
| 
 | ||||
| #include "storeexpr.hh" | ||||
| #include "util.hh" | ||||
| 
 | ||||
| 
 | ||||
| /* Determine the set of "live" store paths, given a set of root store
 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| #include "normalise.hh" | ||||
| #include "build.hh" | ||||
| 
 | ||||
| 
 | ||||
| Derivation derivationFromPath(const Path & drvPath) | ||||
|  |  | |||
|  | @ -2,7 +2,10 @@ | |||
| #include <algorithm> | ||||
| 
 | ||||
| #include <sys/wait.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| #include <utime.h> | ||||
| 
 | ||||
| #include "store.hh" | ||||
| #include "globals.hh" | ||||
|  | @ -181,6 +184,51 @@ void assertStorePath(const Path & path) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void canonicalisePathMetaData(const Path & path) | ||||
| { | ||||
|     checkInterrupt(); | ||||
| 
 | ||||
|     struct stat st; | ||||
|     if (lstat(path.c_str(), &st)) | ||||
| 	throw SysError(format("getting attributes of path `%1%'") % path); | ||||
| 
 | ||||
|     if (!S_ISLNK(st.st_mode)) { | ||||
| 
 | ||||
|         /* Mask out all type related bits. */ | ||||
|         mode_t mode = st.st_mode & ~S_IFMT; | ||||
|          | ||||
|         if (mode != 0444 && mode != 0555) { | ||||
|             mode = (st.st_mode & S_IFMT) | ||||
|                  | 0444 | ||||
|                  | (st.st_mode & S_IXUSR ? 0111 : 0); | ||||
|             if (chmod(path.c_str(), mode) == -1) | ||||
|                 throw SysError(format("changing mode of `%1%' to %2$o") % path % mode); | ||||
|         } | ||||
| 
 | ||||
|         if (st.st_uid != getuid() || st.st_gid != getgid()) { | ||||
|             if (chown(path.c_str(), getuid(), getgid()) == -1) | ||||
|                 throw SysError(format("changing owner/group of `%1%' to %2%/%3%") | ||||
|                     % path % getuid() % getgid()); | ||||
|         } | ||||
| 
 | ||||
|         if (st.st_mtime != 0) { | ||||
|             struct utimbuf utimbuf; | ||||
|             utimbuf.actime = st.st_atime; | ||||
|             utimbuf.modtime = 0; | ||||
|             if (utime(path.c_str(), &utimbuf) == -1)  | ||||
|                 throw SysError(format("changing modification time of `%1%'") % path); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     if (S_ISDIR(st.st_mode)) { | ||||
|         Strings names = readDirectory(path); | ||||
| 	for (Strings::iterator i = names.begin(); i != names.end(); ++i) | ||||
| 	    canonicalisePathMetaData(path + "/" + *i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static bool isValidPathTxn(const Path & path, const Transaction & txn) | ||||
| { | ||||
|     string s; | ||||
|  | @ -318,12 +366,24 @@ void clearSubstitutes() | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void registerValidPath(const Transaction & txn, const Path & _path) | ||||
| void registerValidPath(const Transaction & txn, | ||||
|     const Path & _path, const Hash & hash) | ||||
| { | ||||
|     Path path(canonPath(_path)); | ||||
|     assertStorePath(path); | ||||
| 
 | ||||
|     assert(hash.type == htSHA256); | ||||
|      | ||||
|     debug(format("registering path `%1%'") % path); | ||||
|     nixDB.setString(txn, dbValidPaths, path, ""); | ||||
|     nixDB.setString(txn, dbValidPaths, path, "sha256:" + printHash(hash)); | ||||
| 
 | ||||
|     /* Check that all referenced paths are also valid. */ | ||||
|     Paths references; | ||||
|     nixDB.queryStrings(txn, dbReferences, path, references); | ||||
|     for (Paths::iterator i = references.begin(); i != references.end(); ++i) | ||||
|         if (!isValidPathTxn(*i, txn)) | ||||
|             throw Error(format("cannot register path `%1%' as valid, since its reference `%2%' is invalid") | ||||
|                 % path % *i); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -385,10 +445,10 @@ Path addToStore(const Path & _srcPath) | |||
|                 throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)") | ||||
|                     % srcPath % dstPath % printHash(h) % printHash(h2)); | ||||
| 
 | ||||
|             makePathReadOnly(dstPath); | ||||
|             canonicalisePathMetaData(dstPath); | ||||
|              | ||||
|             Transaction txn(nixDB); | ||||
|             registerValidPath(txn, dstPath); | ||||
|             registerValidPath(txn, dstPath, h); | ||||
|             txn.commit(); | ||||
|         } | ||||
| 
 | ||||
|  | @ -417,10 +477,10 @@ Path addTextToStore(const string & suffix, const string & s) | |||
| 
 | ||||
|             writeStringToFile(dstPath, s); | ||||
| 
 | ||||
|             makePathReadOnly(dstPath); | ||||
|             canonicalisePathMetaData(dstPath); | ||||
|              | ||||
|             Transaction txn(nixDB); | ||||
|             registerValidPath(txn, dstPath); | ||||
|             registerValidPath(txn, dstPath, hashPath(htSHA256, dstPath)); | ||||
|             txn.commit(); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -51,12 +51,28 @@ Substitutes querySubstitutes(const Path & srcPath); | |||
| /* Deregister all substitutes. */ | ||||
| void clearSubstitutes(); | ||||
| 
 | ||||
| /* Register the validity of a path. */ | ||||
| void registerValidPath(const Transaction & txn, const Path & path); | ||||
| /* Register the validity of a path, i.e., that `path' exists, that the
 | ||||
|    paths referenced by it exists, and in the case of an output path of | ||||
|    a derivation, that it has been produced by a succesful execution of | ||||
|    the derivation (or something equivalent).  Also register the hash | ||||
|    of the file system contents of the path.  The hash must be a | ||||
|    SHA-256 hash. */ | ||||
| void registerValidPath(const Transaction & txn, | ||||
|     const Path & path, const Hash & hash); | ||||
| 
 | ||||
| /* Throw an exception if `path' is not directly in the Nix store. */ | ||||
| void assertStorePath(const Path & path); | ||||
| 
 | ||||
| /* "Fix", or canonicalise, the meta-data of the files in a store path
 | ||||
|    after it has been built.  In particular: | ||||
|    - the last modification date on each file is set to 0 (i.e., | ||||
|      00:00:00 1/1/1970 UTC) | ||||
|    - the permissions are set of 444 or 555 (i.e., read-only with or | ||||
|      without execute permission; setuid bits etc. are cleared) | ||||
|    - the owner and group are set to the Nix user and group, if we're | ||||
|      in a setuid Nix installation. */ | ||||
| void canonicalisePathMetaData(const Path & path); | ||||
| 
 | ||||
| /* Checks whether a path is valid. */  | ||||
| bool isValidPath(const Path & path); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #include "profiles.hh" | ||||
| #include "names.hh" | ||||
| #include "globals.hh" | ||||
| #include "normalise.hh" | ||||
| #include "build.hh" | ||||
| #include "shared.hh" | ||||
| #include "parser.hh" | ||||
| #include "eval.hh" | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| #include <iostream> | ||||
| 
 | ||||
| #include "globals.hh" | ||||
| #include "normalise.hh" | ||||
| #include "build.hh" | ||||
| #include "shared.hh" | ||||
| #include "eval.hh" | ||||
| #include "parser.hh" | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| #include "dotgraph.hh" | ||||
| #include "normalise.hh" | ||||
| #include "build.hh" | ||||
| 
 | ||||
| 
 | ||||
| #if 0 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #ifndef __DOTGRAPH_H | ||||
| #define __DOTGRAPH_H | ||||
| 
 | ||||
| #include "storeexpr.hh" | ||||
| #include "util.hh" | ||||
| 
 | ||||
| void printDotGraph(const PathSet & roots); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #include <iostream> | ||||
| 
 | ||||
| #include "globals.hh" | ||||
| #include "normalise.hh" | ||||
| #include "build.hh" | ||||
| #include "gc.hh" | ||||
| #include "archive.hh" | ||||
| #include "shared.hh" | ||||
|  | @ -187,7 +187,7 @@ static void opValidPath(Strings opFlags, Strings opArgs) | |||
|     createStoreTransaction(txn); | ||||
|     for (Strings::iterator i = opArgs.begin(); | ||||
|          i != opArgs.end(); ++i) | ||||
|         registerValidPath(txn, *i); | ||||
|         registerValidPath(txn, *i, hashPath(htSHA256, *i)); | ||||
|     txn.commit(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue