summaryrefslogtreecommitdiff
path: root/nix
diff options
context:
space:
mode:
Diffstat (limited to 'nix')
-rw-r--r--nix/libstore/local-store.cc45
-rw-r--r--nix/libstore/store-api.cc23
-rw-r--r--nix/libstore/store-api.hh6
-rw-r--r--nix/libutil/util.cc7
-rw-r--r--nix/libutil/util.hh3
5 files changed, 70 insertions, 14 deletions
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc
index 6b5c388efc9..c38dd2072d4 100644
--- a/nix/libstore/local-store.cc
+++ b/nix/libstore/local-store.cc
@@ -1336,6 +1336,8 @@ Path LocalStore::importPath(Source & source)
1336 1336
1337 restorePath(unpacked, hashAndReadSource); 1337 restorePath(unpacked, hashAndReadSource);
1338 1338
1339 Hash narHash = hashAndReadSource.hashSink.currentHash().first;
1340
1339 unsigned int magic = readInt(hashAndReadSource); 1341 unsigned int magic = readInt(hashAndReadSource);
1340 if (magic != EXPORT_MAGIC) 1342 if (magic != EXPORT_MAGIC)
1341 throw Error("normalized archive cannot be imported; wrong format"); 1343 throw Error("normalized archive cannot be imported; wrong format");
@@ -1355,21 +1357,36 @@ Path LocalStore::importPath(Source & source)
1355 hashAndReadSource.hashing = false; 1357 hashAndReadSource.hashing = false;
1356 1358
1357 bool haveSignature = readInt(hashAndReadSource) == 1; 1359 bool haveSignature = readInt(hashAndReadSource) == 1;
1360 string signature;
1361 if (haveSignature)
1362 signature = readString(hashAndReadSource);
1358 1363
1359 if (!haveSignature) 1364 try {
1360 throw Error(std::format("imported archive of `{}' lacks a signature", dstPath)); 1365 /* First, check whether there is a valid, authorized, matching
1361 1366 signature. */
1362 string signature = readString(hashAndReadSource); 1367 if (haveSignature) {
1363 string hash2 = verifySignature(signature); 1368 string hash2 = verifySignature(signature);
1364 1369 if (printHash(hash) != hash2)
1365 /* Note: runProgram() throws an exception if the signature 1370 throw AuthenticationError(
1366 is invalid. */ 1371 "signed hash doesn't match actual contents of imported "
1367 1372 "archive; archive could be corrupt, or someone is trying "
1368 if (printHash(hash) != hash2) 1373 "to import a Trojan horse");
1369 throw Error( 1374 }
1370 "signed hash doesn't match actual contents of imported " 1375 else
1371 "archive; archive could be corrupt, or someone is trying " 1376 throw AuthenticationError(std::format("imported archive of `{}' lacks a signature", dstPath));
1372 "to import a Trojan horse"); 1377 }
1378 catch (AuthenticationError &e) {
1379 /* Second, check whether 'dstPath' is content-addressed--e.g., a store
1380 item created by 'addToStore' or 'addTextToStore'. XXX: This can
1381 yield an extra 'hashFile' call and is limited to SHA256. */
1382 if (!(deriver == ""
1383 && (isContentAddressedPath(dstPath, narHash, references, true)
1384 || (isPlainFile(unpacked)
1385 && isContentAddressedPath(dstPath, hashFile(htSHA256, unpacked),
1386 references, false)))))
1387 /* Rethrow. */
1388 throw;
1389 }
1373 1390
1374 /* Do the actual import. */ 1391 /* Do the actual import. */
1375 1392
diff --git a/nix/libstore/store-api.cc b/nix/libstore/store-api.cc
index feabc821678..43f46176b5e 100644
--- a/nix/libstore/store-api.cc
+++ b/nix/libstore/store-api.cc
@@ -258,6 +258,29 @@ Path computeStorePathForText(const string & name, const string & s,
258 return makeStorePath(type, hash, name); 258 return makeStorePath(type, hash, name);
259} 259}
260 260
261bool isContentAddressedPath(const Path & path, const Hash & hash,
262 const PathSet & references, bool recursive)
263{
264 /* Check whether PATH corresponds to something introduced by 'addToStore'
265 or by 'addTextToStore'. For simplicity, anything with a hash other
266 than SHA256 is omitted: this returns false even though they are
267 content-addressed as well. */
268 string name = storePathToName(path);
269 if (recursive) {
270 /* HASH is interpreted as the nar hash. This can only come from
271 'addToStore'. */
272 return references.empty() &&
273 path == makeFixedOutputPath(true, htSHA256, hash, name);
274 } else {
275 /* HASH is interpreted as the content hash. This can come from
276 'addTextToStore' ("text" type, possibly with references) or from
277 'addToStore' ("output:out" type). */
278 string type = textTypeWithReferences(references);
279 return path == makeStorePath(type, hash, name)
280 || (references.empty() &&
281 path == makeFixedOutputPath(false, htSHA256, hash, name));
282 }
283}
261 284
262/* Return a string accepted by decodeValidPathInfo() that 285/* Return a string accepted by decodeValidPathInfo() that
263 registers the specified paths as valid. Note: it's the 286 registers the specified paths as valid. Note: it's the
diff --git a/nix/libstore/store-api.hh b/nix/libstore/store-api.hh
index 29b33c0be9c..398ccd260ea 100644
--- a/nix/libstore/store-api.hh
+++ b/nix/libstore/store-api.hh
@@ -362,6 +362,12 @@ Path makeFixedOutputPath(bool recursive,
362Path computeStorePathForText(const string & name, const string & s, 362Path computeStorePathForText(const string & name, const string & s,
363 const PathSet & references); 363 const PathSet & references);
364 364
365/* Return true if PATH, whose content has the given HASH, refers to a
366 content-addressed file as added by 'addTextToStore' or 'addToStore'. HASH
367 is interpreted as a SHA256 nar hash when RECURSIVE is true, and as a SHA256
368 file content hash when RECURSIVE is false. */
369bool isContentAddressedPath(const Path & path, const Hash & hash,
370 const PathSet & references, bool recursive);
365 371
366/* Remove the temporary roots file for this process. Any temporary 372/* Remove the temporary roots file for this process. Any temporary
367 root becomes garbage after this point unless it has been registered 373 root becomes garbage after this point unless it has been registered
diff --git a/nix/libutil/util.cc b/nix/libutil/util.cc
index 95f293ff10f..72c8d38bd50 100644
--- a/nix/libutil/util.cc
+++ b/nix/libutil/util.cc
@@ -287,6 +287,13 @@ unsigned char getFileType(const Path & path)
287 return DT_UNKNOWN; 287 return DT_UNKNOWN;
288} 288}
289 289
290bool isPlainFile(const Path & path)
291{
292 struct stat st = lstat(path);
293 return S_ISREG(st.st_mode)
294 && ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0);
295}
296
290 297
291string readFile(int fd) 298string readFile(int fd)
292{ 299{
diff --git a/nix/libutil/util.hh b/nix/libutil/util.hh
index 44d579f3d6a..ee8e5461b42 100644
--- a/nix/libutil/util.hh
+++ b/nix/libutil/util.hh
@@ -65,6 +65,9 @@ Path readLink(const Path & path);
65 65
66bool isLink(const Path & path); 66bool isLink(const Path & path);
67 67
68/* Return true if the file at PATH is a regular, non-executable file. */
69bool isPlainFile(const Path & path);
70
68/* Read the contents of a directory. The entries `.' and `..' are 71/* Read the contents of a directory. The entries `.' and `..' are
69 removed. */ 72 removed. */
70struct DirEntry 73struct DirEntry