diff options
author | regnat <rg@regnat.ovh> | 2021-05-27 13:25:25 +0200 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2021-06-01 15:09:24 +0200 |
commit | 5985b8b5275605ddd5e92e2f0a7a9f494ac6e35d (patch) | |
tree | d44bdb69d99952539e01570f2f6dc95ef5e714d8 /src/libstore | |
parent | 48396d940ee0f68080cfe99544a50a884b30fea6 (diff) |
Check the CA hash when importing stuff in the local store
When adding a path to the local store (via `LocalStore::addToStore`),
ensure that the `ca` field of the provided `ValidPathInfo` does indeed
correspond to the content of the path.
Otherwise any untrusted user (or any binary cache) can add arbitrary
content-addressed paths to the store (as content-addressed paths don’t
need a signature).
Diffstat (limited to 'src/libstore')
-rw-r--r-- | src/libstore/local-store.cc | 57 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 13 |
2 files changed, 70 insertions, 0 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 3b99ba39d..efea7bd23 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1168,6 +1168,31 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source, throw Error("size mismatch importing path '%s';\n specified: %s\n got: %s", printStorePath(info.path), info.narSize, hashResult.second); + if (info.ca) { + if (auto foHash = std::get_if<FixedOutputHash>(&*info.ca)) { + auto actualFoHash = hashCAPath( + foHash->method, + foHash->hash.type, + info.path + ); + if (foHash->hash != actualFoHash.hash) { + throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s", + printStorePath(info.path), + foHash->hash.to_string(Base32, true), + actualFoHash.hash.to_string(Base32, true)); + } + } + if (auto textHash = std::get_if<TextHash>(&*info.ca)) { + auto actualTextHash = hashString(htSHA256, readFile(realPath)); + if (textHash->hash != actualTextHash) { + throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s", + printStorePath(info.path), + textHash->hash.to_string(Base32, true), + actualTextHash.to_string(Base32, true)); + } + } + } + autoGC(); canonicalisePathMetaData(realPath, -1); @@ -1672,4 +1697,36 @@ std::optional<const Realisation> LocalStore::queryRealisation( .id = id, .outPath = outputPath, .signatures = signatures}}; }); } + + +FixedOutputHash LocalStore::hashCAPath( + const FileIngestionMethod & method, const HashType & hashType, + const StorePath & path) +{ + return hashCAPath(method, hashType, Store::toRealPath(path), path.hashPart()); +} + +FixedOutputHash LocalStore::hashCAPath( + const FileIngestionMethod & method, + const HashType & hashType, + const Path & path, + const std::string_view pathHash +) +{ + HashModuloSink caSink ( hashType, std::string(pathHash) ); + switch (method) { + case FileIngestionMethod::Recursive: + dumpPath(path, caSink); + break; + case FileIngestionMethod::Flat: + readFile(path, caSink); + break; + } + auto hash = caSink.finish().first; + return FixedOutputHash{ + .method = method, + .hash = hash, + }; +} + } // namespace nix diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 26e034a82..c0b8e0da6 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -283,6 +283,19 @@ private: void createUser(const std::string & userName, uid_t userId) override; + // XXX: Make a generic `Store` method + FixedOutputHash hashCAPath( + const FileIngestionMethod & method, + const HashType & hashType, + const StorePath & path); + + FixedOutputHash hashCAPath( + const FileIngestionMethod & method, + const HashType & hashType, + const Path & path, + const std::string_view pathHash + ); + friend struct LocalDerivationGoal; friend struct PathSubstitutionGoal; friend struct SubstitutionGoal; |