From: Ondřej Surý Date: Thu, 4 Apr 2019 11:51:09 +0000 (+0200) Subject: Convert isc_hash functions to use isc_siphash24 X-Git-Tag: v9.15.1~38^2~2 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=2e7d82443fa415398f37e145325cca26d501a942;p=thirdparty%2Fbind9.git Convert isc_hash functions to use isc_siphash24 --- diff --git a/bin/tests/system/dyndb/driver/driver.c b/bin/tests/system/dyndb/driver/driver.c index 0f6b18d4389..4e68194428f 100644 --- a/bin/tests/system/dyndb/driver/driver.c +++ b/bin/tests/system/dyndb/driver/driver.c @@ -78,10 +78,9 @@ dyndb_init(isc_mem_t *mctx, const char *name, const char *parameters, isc_lib_register(); isc_log_setcontext(dctx->lctx); dns_log_setcontext(dctx->lctx); + isc_hash_set_initializer(dctx->hashinit); } - isc_hash_set_initializer(dctx->hashinit); - s = isc_mem_strdup(mctx, parameters); if (s == NULL) { result = ISC_R_NOMEMORY; diff --git a/lib/dns/name.c b/lib/dns/name.c index 7709c4a645e..dcea87e1b23 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -464,7 +464,7 @@ dns_name_hash(const dns_name_t *name, bool case_sensitive) { length = 16; return (isc_hash_function_reverse(name->ndata, length, - case_sensitive, NULL)); + case_sensitive)); } unsigned int @@ -478,7 +478,7 @@ dns_name_fullhash(const dns_name_t *name, bool case_sensitive) { return (0); return (isc_hash_function_reverse(name->ndata, name->length, - case_sensitive, NULL)); + case_sensitive)); } dns_namereln_t diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index b8911514037..5b3518a2963 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -9653,7 +9653,7 @@ rehash_gluetable(rbtdb_version_t *version) { { hash = isc_hash_function(&gluenode->node, sizeof(gluenode->node), - true, NULL) % + true) % version->glue_table_size; nextgluenode = gluenode->next; gluenode->next = version->glue_table[hash]; @@ -9821,7 +9821,7 @@ rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, * the node pointer is a fixed value that won't change for a DB * version and can be compared directly. */ - idx = isc_hash_function(&node, sizeof(node), true, NULL) % + idx = isc_hash_function(&node, sizeof(node), true) % rbtversion->glue_table_size; restart: @@ -9997,8 +9997,7 @@ no_glue: RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write); if (ISC_UNLIKELY(rehash_gluetable(rbtversion))) { - idx = isc_hash_function(&node, sizeof(node), - true, NULL) % + idx = isc_hash_function(&node, sizeof(node), true) % rbtversion->glue_table_size; } diff --git a/lib/isc/hash.c b/lib/isc/hash.c index d37f24b6b27..4d9857889b6 100644 --- a/lib/isc/hash.c +++ b/lib/isc/hash.c @@ -16,6 +16,9 @@ #include #include #include +#if defined(WIN32) || defined(WIN64) +#include +#endif #include "isc/hash.h" // IWYU pragma: keep #include "isc/likely.h" @@ -24,12 +27,31 @@ #include "isc/result.h" #include "isc/types.h" #include "isc/util.h" +#include "isc/siphash.h" +#include "isc/string.h" -static uint32_t fnv_offset_basis; -static isc_once_t fnv_once = ISC_ONCE_INIT; -static bool fnv_initialized = false; +#include "entropy_private.h" -static unsigned char maptolower[] = { +static uint8_t isc_hash_key[16]; +static bool hash_initialized = false; +static isc_once_t isc_hash_once = ISC_ONCE_INIT; + +static void +isc_hash_initialize(void) { + uint64_t key[2] = { 0, 1 }; +#if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* + * Set a constant key to help in problem reproduction should + * fuzzing find a crash or a hang. + */ +#else + isc_entropy_get(key, sizeof(key)); +#endif + memmove(isc_hash_key, key, sizeof(isc_hash_key)); + hash_initialized = true; +} + +static uint8_t maptolower[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, @@ -64,27 +86,15 @@ static unsigned char maptolower[] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; -static void -fnv_initialize(void) { - /* - * This function should not leave fnv_offset_basis set to - * 0. Also, after this function has been called, if it is called - * again, it should not change fnv_offset_basis. - */ - while (fnv_offset_basis == 0) { - fnv_offset_basis = isc_random32(); - } - - fnv_initialized = true; -} - const void * isc_hash_get_initializer(void) { - if (ISC_UNLIKELY(!fnv_initialized)) - RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == - ISC_R_SUCCESS); + if (ISC_UNLIKELY(!hash_initialized)) { + RUNTIME_CHECK(isc_once_do(&isc_hash_once, + isc_hash_initialize) + == ISC_R_SUCCESS); + } - return (&fnv_offset_basis); + return (isc_hash_key); } void @@ -92,112 +102,70 @@ isc_hash_set_initializer(const void *initializer) { REQUIRE(initializer != NULL); /* - * Ensure that fnv_initialize() is not called after + * Ensure that isc_hash_initialize() is not called after * isc_hash_set_initializer() is called. */ - if (ISC_UNLIKELY(!fnv_initialized)) - RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == - ISC_R_SUCCESS); + if (ISC_UNLIKELY(!hash_initialized)) { + RUNTIME_CHECK(isc_once_do(&isc_hash_once, + isc_hash_initialize) + == ISC_R_SUCCESS); + } - fnv_offset_basis = *((const unsigned int *)initializer); + memmove(isc_hash_key, initializer, sizeof(isc_hash_key)); } -#define FNV_32_PRIME ((uint32_t)0x01000193) - -uint32_t -isc_hash_function(const void *data, size_t length, bool case_sensitive, - const uint32_t *previous_hashp) +uint64_t +isc_hash_function(const void *data, const size_t length, + const bool case_sensitive) { - uint32_t hval; - const unsigned char *bp; - const unsigned char *be; + uint64_t hval; REQUIRE(length == 0 || data != NULL); - if (ISC_UNLIKELY(!fnv_initialized)) { - RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == - ISC_R_SUCCESS); - } - - hval = ISC_UNLIKELY(previous_hashp != NULL) ? *previous_hashp - : fnv_offset_basis; - - if (length == 0) { - return (hval); - } - - bp = (const unsigned char *)data; - be = bp + length; - - /* - * Fowler-Noll-Vo FNV-1a hash function. - * - * NOTE: A random FNV offset basis is used by default to avoid - * collision attacks as the hash function is reversible. This - * makes the mapping non-deterministic, but the distribution in - * the domain is still uniform. - */ + RUNTIME_CHECK(isc_once_do(&isc_hash_once, + isc_hash_initialize) == ISC_R_SUCCESS); if (case_sensitive) { - while (bp < be) { - hval ^= *bp++; - hval *= FNV_32_PRIME; - } + isc_siphash24(isc_hash_key, data, length, (uint8_t *)&hval); } else { - while (bp < be) { - hval ^= maptolower[*bp++]; - hval *= FNV_32_PRIME; + uint8_t input[1024]; + REQUIRE(length <= 1024); + for (unsigned int i = 0; i < length; i++) { + input[i] = maptolower[((const uint8_t *)data)[i]]; } + isc_siphash24(isc_hash_key, input, length, (uint8_t *)&hval); } return (hval); } -uint32_t -isc_hash_function_reverse(const void *data, size_t length, bool case_sensitive, - const uint32_t *previous_hashp) +uint64_t +isc_hash_function_reverse(const void *data, const size_t length, + const bool case_sensitive) { - uint32_t hval; - const unsigned char *bp; - const unsigned char *be; + uint64_t hval; +#if defined(WIN32) || defined(WIN64) + uint8_t *input = _alloca(length); + INSIST(buf != NULL); +#else + uint8_t input[length]; +#endif REQUIRE(length == 0 || data != NULL); - if (ISC_UNLIKELY(!fnv_initialized)) { - RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == - ISC_R_SUCCESS); - } - - hval = ISC_UNLIKELY(previous_hashp != NULL) ? *previous_hashp - : fnv_offset_basis; - - if (length == 0) { - return (hval); - } - - bp = (const unsigned char *)data; - be = bp + length; - - /* - * Fowler-Noll-Vo FNV-1a hash function. - * - * NOTE: A random FNV offset basis is used by default to avoid - * collision attacks as the hash function is reversible. This - * makes the mapping non-deterministic, but the distribution in - * the domain is still uniform. - */ + RUNTIME_CHECK(isc_once_do(&isc_hash_once, + isc_hash_initialize) == ISC_R_SUCCESS); if (case_sensitive) { - while (--be >= bp) { - hval ^= *be; - hval *= FNV_32_PRIME; + for (unsigned int i = 0, j = length - 1; i < length; i++, j--) { + input[i] = ((const uint8_t *)data)[j]; } } else { - while (--be >= bp) { - hval ^= maptolower[*be]; - hval *= FNV_32_PRIME; + for (unsigned int i = 0, j = length - 1; i < length; i++, j--) { + input[i] = maptolower[((const uint8_t *)data)[j]]; } } + isc_siphash24(isc_hash_key, input, length, (uint8_t *)&hval); return (hval); } diff --git a/lib/isc/ht.c b/lib/isc/ht.c index e8e3eb12d55..2275bab0185 100644 --- a/lib/isc/ht.c +++ b/lib/isc/ht.c @@ -128,7 +128,7 @@ isc_ht_add(isc_ht_t *ht, const unsigned char *key, REQUIRE(ISC_HT_VALID(ht)); REQUIRE(key != NULL && keysize > 0); - hash = isc_hash_function(key, keysize, true, NULL); + hash = isc_hash_function(key, keysize, true); node = ht->table[hash & ht->mask]; while (node != NULL) { if (keysize == node->keysize && @@ -163,7 +163,7 @@ isc_ht_find(const isc_ht_t *ht, const unsigned char *key, REQUIRE(key != NULL && keysize > 0); REQUIRE(valuep == NULL || *valuep == NULL); - hash = isc_hash_function(key, keysize, true, NULL); + hash = isc_hash_function(key, keysize, true); node = ht->table[hash & ht->mask]; while (node != NULL) { if (keysize == node->keysize && @@ -188,7 +188,7 @@ isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize) { REQUIRE(key != NULL && keysize > 0); prev = NULL; - hash = isc_hash_function(key, keysize, true, NULL); + hash = isc_hash_function(key, keysize, true); node = ht->table[hash & ht->mask]; while (node != NULL) { if (keysize == node->keysize && @@ -303,8 +303,7 @@ isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) { it->cur = ht->table[it->i]; } - hash = isc_hash_function(to_delete->key, to_delete->keysize, true, - NULL); + hash = isc_hash_function(to_delete->key, to_delete->keysize, true); node = ht->table[hash & ht->mask]; while (node != to_delete) { prev = node; diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h index 5b4336e68ed..f1c1f57450f 100644 --- a/lib/isc/include/isc/hash.h +++ b/lib/isc/include/isc/hash.h @@ -29,14 +29,10 @@ isc_hash_get_initializer(void); void isc_hash_set_initializer(const void *initializer); -uint32_t -isc_hash_function(const void *data, size_t length, - bool case_sensitive, - const uint32_t *previous_hashp); -uint32_t -isc_hash_function_reverse(const void *data, size_t length, - bool case_sensitive, - const uint32_t *previous_hashp); +uint64_t +isc_hash_function(const void *data, const size_t length, const bool case_sensitive); +uint64_t +isc_hash_function_reverse(const void *data, const size_t length, const bool case_sensitive); /*!< * \brief Calculate a hash over data. * diff --git a/lib/isc/mem.c b/lib/isc/mem.c index 44afca052fa..923bec045bf 100644 --- a/lib/isc/mem.c +++ b/lib/isc/mem.c @@ -261,7 +261,7 @@ add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) { if (mctx->debuglist == NULL) return; - hash = isc_hash_function(&ptr, sizeof(ptr), true, NULL); + hash = isc_hash_function(&ptr, sizeof(ptr), true); idx = hash % DEBUG_TABLE_COUNT; dl = malloc(sizeof(debuglink_t)); @@ -296,7 +296,7 @@ delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size, if (mctx->debuglist == NULL) return; - hash = isc_hash_function(&ptr, sizeof(ptr), true, NULL); + hash = isc_hash_function(&ptr, sizeof(ptr), true); idx = hash % DEBUG_TABLE_COUNT; dl = ISC_LIST_HEAD(mctx->debuglist[idx]); diff --git a/lib/isc/sockaddr.c b/lib/isc/sockaddr.c index 60b74b1b98b..832be1c2ce0 100644 --- a/lib/isc/sockaddr.c +++ b/lib/isc/sockaddr.c @@ -14,6 +14,9 @@ #include #include +#if defined(WIN32) || defined(WIN64) +#include +#endif #include #include @@ -222,9 +225,14 @@ isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) { p = 0; } - h = isc_hash_function(s, length, true, NULL); - if (!address_only) - h = isc_hash_function(&p, sizeof(p), true, &h); + uint8_t buf[sizeof(struct sockaddr_storage) + sizeof(p)]; + memmove(buf, s, length); + if (!address_only) { + memmove(buf + length, &p, sizeof(p)); + h = isc_hash_function(buf, length + sizeof(p), true); + } else { + h = isc_hash_function(buf, length, true); + } return (h); } diff --git a/lib/isc/tests/hash_test.c b/lib/isc/tests/hash_test.c index aa368b99a84..056197a4454 100644 --- a/lib/isc/tests/hash_test.c +++ b/lib/isc/tests/hash_test.c @@ -37,13 +37,6 @@ #define TEST_INPUT(x) (x), sizeof(x)-1 -typedef struct hash_testcase { - const char *input; - size_t input_len; - const char *result; - int repeats; -} hash_testcase_t; - /*Hash function test */ static void isc_hash_function_test(void **state) { @@ -52,39 +45,27 @@ isc_hash_function_test(void **state) { UNUSED(state); - /* Incremental hashing */ - - h1 = isc_hash_function(NULL, 0, true, NULL); - h1 = isc_hash_function("This ", 5, true, &h1); - h1 = isc_hash_function("is ", 3, true, &h1); - h1 = isc_hash_function("a long test", 12, true, &h1); - - h2 = isc_hash_function("This is a long test", 20, - true, NULL); - - assert_int_equal(h1, h2); - /* Immutability of hash function */ - h1 = isc_hash_function(NULL, 0, true, NULL); - h2 = isc_hash_function(NULL, 0, true, NULL); + h1 = isc_hash_function(NULL, 0, true); + h2 = isc_hash_function(NULL, 0, true); assert_int_equal(h1, h2); /* Hash function characteristics */ - h1 = isc_hash_function("Hello world", 12, true, NULL); - h2 = isc_hash_function("Hello world", 12, true, NULL); + h1 = isc_hash_function("Hello world", 12, true); + h2 = isc_hash_function("Hello world", 12, true); assert_int_equal(h1, h2); /* Case */ - h1 = isc_hash_function("Hello world", 12, false, NULL); - h2 = isc_hash_function("heLLo WorLd", 12, false, NULL); + h1 = isc_hash_function("Hello world", 12, false); + h2 = isc_hash_function("heLLo WorLd", 12, false); assert_int_equal(h1, h2); /* Unequal */ - h1 = isc_hash_function("Hello world", 12, true, NULL); - h2 = isc_hash_function("heLLo WorLd", 12, true, NULL); + h1 = isc_hash_function("Hello world", 12, true); + h2 = isc_hash_function("heLLo WorLd", 12, true); assert_int_not_equal(h1, h2); } @@ -97,39 +78,27 @@ isc_hash_function_reverse_test(void **state) { UNUSED(state); - /* Incremental hashing */ - - h1 = isc_hash_function_reverse(NULL, 0, true, NULL); - h1 = isc_hash_function_reverse("\000", 1, true, &h1); - h1 = isc_hash_function_reverse("\003org", 4, true, &h1); - h1 = isc_hash_function_reverse("\007example", 8, true, &h1); - - h2 = isc_hash_function_reverse("\007example\003org\000", 13, - true, NULL); - - assert_int_equal(h1, h2); - /* Immutability of hash function */ - h1 = isc_hash_function_reverse(NULL, 0, true, NULL); - h2 = isc_hash_function_reverse(NULL, 0, true, NULL); + h1 = isc_hash_function_reverse(NULL, 0, true); + h2 = isc_hash_function_reverse(NULL, 0, true); assert_int_equal(h1, h2); /* Hash function characteristics */ - h1 = isc_hash_function_reverse("Hello world", 12, true, NULL); - h2 = isc_hash_function_reverse("Hello world", 12, true, NULL); + h1 = isc_hash_function_reverse("Hello world", 12, true); + h2 = isc_hash_function_reverse("Hello world", 12, true); assert_int_equal(h1, h2); /* Case */ - h1 = isc_hash_function_reverse("Hello world", 12, false, NULL); - h2 = isc_hash_function_reverse("heLLo WorLd", 12, false, NULL); + h1 = isc_hash_function_reverse("Hello world", 12, false); + h2 = isc_hash_function_reverse("heLLo WorLd", 12, false); assert_int_equal(h1, h2); /* Unequal */ - h1 = isc_hash_function_reverse("Hello world", 12, true, NULL); - h2 = isc_hash_function_reverse("heLLo WorLd", 12, true, NULL); + h1 = isc_hash_function_reverse("Hello world", 12, true); + h2 = isc_hash_function_reverse("heLLo WorLd", 12, true); assert_true(h1 != h2); } @@ -142,15 +111,15 @@ isc_hash_initializer_test(void **state) { UNUSED(state); - h1 = isc_hash_function("Hello world", 12, true, NULL); - h2 = isc_hash_function("Hello world", 12, true, NULL); + h1 = isc_hash_function("Hello world", 12, true); + h2 = isc_hash_function("Hello world", 12, true); assert_int_equal(h1, h2); isc_hash_set_initializer(isc_hash_get_initializer()); /* Hash value must not change */ - h2 = isc_hash_function("Hello world", 12, true, NULL); + h2 = isc_hash_function("Hello world", 12, true); assert_int_equal(h1, h2); } diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in index 195a24c94cc..fefa06be0da 100644 --- a/lib/isc/win32/libisc.def.in +++ b/lib/isc/win32/libisc.def.in @@ -232,7 +232,6 @@ isc_fsaccess_changeowner isc_fsaccess_remove isc_fsaccess_set isc_hash_function -isc_hash_function_reverse isc_hash_get_initializer isc_hash_set_initializer isc_heap_create