]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Convert isc_hash functions to use isc_siphash24
authorOndřej Surý <ondrej@sury.org>
Thu, 4 Apr 2019 11:51:09 +0000 (13:51 +0200)
committerOndřej Surý <ondrej@sury.org>
Tue, 21 May 2019 10:23:13 +0000 (10:23 +0000)
bin/tests/system/dyndb/driver/driver.c
lib/dns/name.c
lib/dns/rbtdb.c
lib/isc/hash.c
lib/isc/ht.c
lib/isc/include/isc/hash.h
lib/isc/mem.c
lib/isc/sockaddr.c
lib/isc/tests/hash_test.c
lib/isc/win32/libisc.def.in

index 0f6b18d4389c388e2c882cf82477d0df3178f93a..4e68194428f0087d9ae2694e9c4c88b30c2daa07 100644 (file)
@@ -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;
index 7709c4a645e53f32b12d7550bc99b5c74c755b98..dcea87e1b2355a61b82da022081025cda8002044 100644 (file)
@@ -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
index b89115140373fc658028ccf305fbd0cef3b23a60..5b3518a2963ed284ada3a35754edee2d05acae91 100644 (file)
@@ -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;
        }
 
index d37f24b6b27fdd2361f7a978130b810a42f11f91..4d9857889b64543bfae4d3371e93afa5907aa735 100644 (file)
@@ -16,6 +16,9 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <inttypes.h>
+#if defined(WIN32) || defined(WIN64)
+#include <malloc.h>
+#endif
 
 #include "isc/hash.h" // IWYU pragma: keep
 #include "isc/likely.h"
 #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);
 }
index e8e3eb12d55b1cf0adedf3786cb8fb8708afb39a..2275bab01850405ac3ffcfcc7c30756f0eea21c5 100644 (file)
@@ -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;
index 5b4336e68ed6adb8d583a9a7ddf372b853229743..f1c1f57450f22b9bb20395bb5a09a97c0693c8c9 100644 (file)
@@ -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.
  *
index 44afca052fa73fd0502a78ccb016df58d68c7da0..923bec045bfa75df074cbd7cb77b87423742fd4b 100644 (file)
@@ -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]);
index 60b74b1b98b669cb31157778119aeb05f23a52e8..832be1c2ce0e28811479ebe6c588c27b4cb38fbd 100644 (file)
@@ -14,6 +14,9 @@
 
 #include <stdbool.h>
 #include <stdio.h>
+#if defined(WIN32) || defined(WIN64)
+#include <malloc.h>
+#endif
 
 #include <isc/buffer.h>
 #include <isc/hash.h>
@@ -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);
 }
index aa368b99a849cc10972ae44519d7b19bb2bc7f9d..056197a4454b31d96d42d74739aa626b259541aa 100644 (file)
 
 #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);
 }
index 195a24c94cc0ebb87efdc193f91ec716852b9063..fefa06be0dac852a938a8b478a63e9623cb37657 100644 (file)
@@ -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