From 507aa48739f23f9a16c8b7079bfa6fc1806be78e Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 19 Jun 2020 18:41:33 +0000 Subject: WIP: Make Hash always store a valid hash type --- src/libutil/hash.cc | 68 ++++++++++++++++++++++++++++------------------------- src/libutil/hash.hh | 17 ++++++-------- 2 files changed, 43 insertions(+), 42 deletions(-) (limited to 'src/libutil') diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index e49eb4569..35a449530 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -16,16 +16,19 @@ namespace nix { +static size_t regularHashSize(HashType type) { + switch (type) { + case htMD5: return md5HashSize; + case htSHA1: return sha1HashSize; + case htSHA256: return sha256HashSize; + case htSHA512: return sha512HashSize; + } + abort(); +} void Hash::init() { - if (!type) abort(); - switch (*type) { - case htMD5: hashSize = md5HashSize; break; - case htSHA1: hashSize = sha1HashSize; break; - case htSHA256: hashSize = sha256HashSize; break; - case htSHA512: hashSize = sha512HashSize; break; - } + hashSize = regularHashSize(type); assert(hashSize <= maxHashSize); memset(hash, 0, maxHashSize); } @@ -105,18 +108,11 @@ string printHash16or32(const Hash & hash) } -HashType assertInitHashType(const Hash & h) { - if (h.type) - return *h.type; - else - abort(); -} - std::string Hash::to_string(Base base, bool includeType) const { std::string s; if (base == SRI || includeType) { - s += printHashType(assertInitHashType(*this)); + s += printHashType(type); s += base == SRI ? '-' : ':'; } switch (base) { @@ -137,31 +133,39 @@ std::string Hash::to_string(Base base, bool includeType) const Hash::Hash(std::string_view s, HashType type) : Hash(s, std::optional { type }) { } Hash::Hash(std::string_view s) : Hash(s, std::optional{}) { } -Hash::Hash(std::string_view s, std::optional type) - : type(type) +Hash::Hash(std::string_view s, std::optional optType) { size_t pos = 0; bool isSRI = false; + // Find the : or - separater, and set `isSRI` to the correct value auto sep = s.find(':'); - if (sep == string::npos) { + if (sep == std::string_view::npos) { sep = s.find('-'); - if (sep != string::npos) { + if (sep != std::string_view::npos) isSRI = true; - } else if (! type) - throw BadHash("hash '%s' does not include a type", s); } - if (sep != string::npos) { - string hts = string(s, 0, sep); - this->type = parseHashType(hts); - if (!this->type) + // Parse the has type before the separater, if there was one. + std::optional optParsedType; + if (sep != std::string_view::npos) { + auto hts = s.substr(0, sep); + auto optParsedType = parseHashTypeOpt(hts); + if (!optParsedType) throw BadHash("unknown hash type '%s'", hts); - if (type && type != this->type) - throw BadHash("hash '%s' should have type '%s'", s, printHashType(*type)); pos = sep + 1; } + // Either the string or user must provide the type, if they both do they + // must agree. + if (!optParsedType && !optType) { + throw BadHash("hash '%s' does not include a type, nor is the type otherwise known from context.", s); + } else { + this->type = optParsedType ? *optParsedType : *optType; + if (optParsedType && optType && *optParsedType != *optType) + throw BadHash("hash '%s' should have type '%s'", s, printHashType(*optType)); + } + init(); size_t size = s.size() - pos; @@ -214,7 +218,7 @@ Hash::Hash(std::string_view s, std::optional type) } else - throw BadHash("hash '%s' has wrong length for hash type '%s'", s, printHashType(*type)); + throw BadHash("hash '%s' has wrong length for hash type '%s'", s, printHashType(type)); } Hash newHashAllowEmpty(std::string hashStr, std::optional ht) @@ -267,7 +271,7 @@ static void finish(HashType ht, Ctx & ctx, unsigned char * hash) } -Hash hashString(HashType ht, const string & s) +Hash hashString(HashType ht, std::string_view s) { Ctx ctx; Hash hash(ht); @@ -334,7 +338,7 @@ HashResult hashPath( Hash compressHash(const Hash & hash, unsigned int newSize) { - Hash h; + Hash h(hash.type); h.hashSize = newSize; for (unsigned int i = 0; i < hash.hashSize; ++i) h.hash[i % newSize] ^= hash.hash[i]; @@ -342,7 +346,7 @@ Hash compressHash(const Hash & hash, unsigned int newSize) } -std::optional parseHashTypeOpt(const string & s) +std::optional parseHashTypeOpt(std::string_view s) { if (s == "md5") return htMD5; else if (s == "sha1") return htSHA1; @@ -351,7 +355,7 @@ std::optional parseHashTypeOpt(const string & s) else return std::optional {}; } -HashType parseHashType(const string & s) +HashType parseHashType(std::string_view s) { auto opt_h = parseHashTypeOpt(s); if (opt_h) diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh index 0d9916508..b51850ccf 100644 --- a/src/libutil/hash.hh +++ b/src/libutil/hash.hh @@ -25,14 +25,11 @@ enum Base : int { Base64, Base32, Base16, SRI }; struct Hash { - static const unsigned int maxHashSize = 64; - unsigned int hashSize = 0; - unsigned char hash[maxHashSize] = {}; + constexpr static size_t maxHashSize = 64; + size_t hashSize = 0; + uint8_t hash[maxHashSize] = {}; - std::optional type = {}; - - /* Create an unset hash object. */ - Hash() { }; + HashType type; /* Create a zero-filled hash object. */ Hash(HashType type) : type(type) { init(); }; @@ -105,7 +102,7 @@ Hash newHashAllowEmpty(std::string hashStr, std::optional ht); string printHash16or32(const Hash & hash); /* Compute the hash of the given string. */ -Hash hashString(HashType ht, const string & s); +Hash hashString(HashType ht, std::string_view s); /* Compute the hash of the given file. */ Hash hashFile(HashType ht, const Path & path); @@ -121,9 +118,9 @@ HashResult hashPath(HashType ht, const Path & path, Hash compressHash(const Hash & hash, unsigned int newSize); /* Parse a string representing a hash type. */ -HashType parseHashType(const string & s); +HashType parseHashType(std::string_view s); /* Will return nothing on parse error */ -std::optional parseHashTypeOpt(const string & s); +std::optional parseHashTypeOpt(std::string_view s); /* And the reverse. */ string printHashType(HashType ht); -- cgit v1.2.3 From ec3a85730742497b29782c0b545911eb78d3c65e Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 23 Jun 2020 18:19:40 +0000 Subject: Fix and clean up hash parser --- src/libutil/hash.cc | 62 ++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 32 deletions(-) (limited to 'src/libutil') diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index f44210737..70a18f9a0 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -133,68 +133,66 @@ std::string Hash::to_string(Base base, bool includeType) const Hash::Hash(std::string_view s, HashType type) : Hash(s, std::optional { type }) { } Hash::Hash(std::string_view s) : Hash(s, std::optional{}) { } -Hash::Hash(std::string_view s, std::optional optType) +Hash::Hash(std::string_view original, std::optional optType) { + auto rest = original; + size_t pos = 0; bool isSRI = false; - // Find the : or - separater, and set `isSRI` to the correct value - auto sep = s.find(':'); - if (sep == std::string_view::npos) { - sep = s.find('-'); - if (sep != std::string_view::npos) - isSRI = true; - } - // Parse the has type before the separater, if there was one. std::optional optParsedType; - if (sep != std::string_view::npos) { - auto hts = s.substr(0, sep); - auto optParsedType = parseHashTypeOpt(hts); - if (!optParsedType) - throw BadHash("unknown hash type '%s'", hts); - pos = sep + 1; + { + auto sep = rest.find(':'); + if (sep == std::string_view::npos) { + sep = rest.find('-'); + if (sep != std::string_view::npos) + isSRI = true; + } + if (sep != std::string_view::npos) { + auto hashRaw = rest.substr(0, sep); + optParsedType = parseHashType(hashRaw); + rest = rest.substr(sep + 1); + } } // Either the string or user must provide the type, if they both do they // must agree. if (!optParsedType && !optType) { - throw BadHash("hash '%s' does not include a type, nor is the type otherwise known from context.", s); + throw BadHash("hash '%s' does not include a type, nor is the type otherwise known from context.", rest); } else { this->type = optParsedType ? *optParsedType : *optType; if (optParsedType && optType && *optParsedType != *optType) - throw BadHash("hash '%s' should have type '%s'", s, printHashType(*optType)); + throw BadHash("hash '%s' should have type '%s'", original, printHashType(*optType)); } init(); - size_t size = s.size() - pos; - - if (!isSRI && size == base16Len()) { + if (!isSRI && rest.size() == base16Len()) { auto parseHexDigit = [&](char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; if (c >= 'a' && c <= 'f') return c - 'a' + 10; - throw BadHash("invalid base-16 hash '%s'", s); + throw BadHash("invalid base-16 hash '%s'", original); }; for (unsigned int i = 0; i < hashSize; i++) { hash[i] = - parseHexDigit(s[pos + i * 2]) << 4 - | parseHexDigit(s[pos + i * 2 + 1]); + parseHexDigit(rest[pos + i * 2]) << 4 + | parseHexDigit(rest[pos + i * 2 + 1]); } } - else if (!isSRI && size == base32Len()) { + else if (!isSRI && rest.size() == base32Len()) { - for (unsigned int n = 0; n < size; ++n) { - char c = s[pos + size - n - 1]; + for (unsigned int n = 0; n < rest.size(); ++n) { + char c = rest[rest.size() - n - 1]; unsigned char digit; for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */ if (base32Chars[digit] == c) break; if (digit >= 32) - throw BadHash("invalid base-32 hash '%s'", s); + throw BadHash("invalid base-32 hash '%s'", original); unsigned int b = n * 5; unsigned int i = b / 8; unsigned int j = b % 8; @@ -204,21 +202,21 @@ Hash::Hash(std::string_view s, std::optional optType) hash[i + 1] |= digit >> (8 - j); } else { if (digit >> (8 - j)) - throw BadHash("invalid base-32 hash '%s'", s); + throw BadHash("invalid base-32 hash '%s'", original); } } } - else if (isSRI || size == base64Len()) { - auto d = base64Decode(s.substr(pos)); + else if (isSRI || rest.size() == base64Len()) { + auto d = base64Decode(rest); if (d.size() != hashSize) - throw BadHash("invalid %s hash '%s'", isSRI ? "SRI" : "base-64", s); + throw BadHash("invalid %s hash '%s'", isSRI ? "SRI" : "base-64", original); assert(hashSize); memcpy(hash, d.data(), hashSize); } else - throw BadHash("hash '%s' has wrong length for hash type '%s'", s, printHashType(type)); + throw BadHash("hash '%s' has wrong length for hash type '%s'", rest, printHashType(this->type)); } Hash newHashAllowEmpty(std::string hashStr, std::optional ht) -- cgit v1.2.3 From 2292814049256980c6e809ab364ebe0da3c9d76a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 24 Jul 2020 11:19:17 +0200 Subject: createUnixDomainSocket(): Fix off-by-one error in copying the socket path Reported by Kane York. --- src/libutil/util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libutil') diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 93798a765..a0a8ff4d3 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1581,7 +1581,7 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) struct sockaddr_un addr; addr.sun_family = AF_UNIX; - if (path.size() >= sizeof(addr.sun_path)) + if (path.size() + 1 >= sizeof(addr.sun_path)) throw Error("socket path '%1%' is too long", path); strcpy(addr.sun_path, path.c_str()); -- cgit v1.2.3