Skip to content

Commit

Permalink
Cleanup how the initial hash value is seeded
Browse files Browse the repository at this point in the history
  • Loading branch information
lpereira committed May 18, 2024
1 parent e380a94 commit 5472927
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/bin/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ else ()
mimegen.c
${CMAKE_SOURCE_DIR}/src/lib/hash.c
${CMAKE_SOURCE_DIR}/src/lib/missing.c
${CMAKE_SOURCE_DIR}/src/lib/lwan-status.c
)
if (LWAN_HAVE_BROTLI)
message(STATUS "Using Brotli for mimegen")
Expand Down
48 changes: 33 additions & 15 deletions src/lib/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,22 @@ struct hash_entry {
static_assert((MIN_BUCKETS & (MIN_BUCKETS - 1)) == 0,
"Bucket size is power of 2");

#define DEFAULT_FNV1A_64_SEED 0xcbf29ce484222325ull
#define DEFAULT_FNV1A_32_SEED 0x811c9dc5u

uint64_t fnv1a_64_seed = DEFAULT_FNV1A_64_SEED;
uint32_t fnv1a_32_seed = DEFAULT_FNV1A_32_SEED;

#define ASSERT_SEED_INITIALIZED() \
do { \
assert(fnv1a_64_seed != DEFAULT_FNV1A_64_SEED); \
assert(fnv1a_32_seed != DEFAULT_FNV1A_32_SEED); \
} while (0)

static inline unsigned int hash_fnv1a_32(const void *keyptr);
static inline unsigned int hash_int_32(const void *keyptr);
static inline unsigned int hash_int_64(const void *keyptr);

static unsigned int odd_constant = DEFAULT_ODD_CONSTANT;
static unsigned (*hash_str)(const void *key) = hash_fnv1a_32;
static unsigned (*hash_int)(const void *key) = hash_int_32;
static unsigned (*hash_int64)(const void *key) = hash_int_64;
Expand Down Expand Up @@ -135,10 +146,12 @@ static inline unsigned int hash_int_64(const void *keyptr)
#if defined(LWAN_HAVE_BUILTIN_CPU_INIT) && defined(LWAN_HAVE_BUILTIN_IA32_CRC32)
static inline unsigned int hash_str_crc32(const void *keyptr)
{
unsigned int hash = odd_constant;
unsigned int hash = fnv1a_32_seed;
const char *key = keyptr;
size_t len = strlen(key);

ASSERT_SEED_INITIALIZED();

#if __x86_64__
while (len >= sizeof(uint64_t)) {
uint64_t data;
Expand Down Expand Up @@ -171,20 +184,24 @@ static inline unsigned int hash_str_crc32(const void *keyptr)

static inline unsigned int hash_int_crc32(const void *keyptr)
{
return __builtin_ia32_crc32si(odd_constant,
ASSERT_SEED_INITIALIZED();

return __builtin_ia32_crc32si(fnv1a_32_seed,
(unsigned int)(uintptr_t)keyptr);
}

static inline unsigned int hash_int64_crc32(const void *keyptr)
{
ASSERT_SEED_INITIALIZED();

#ifdef __x86_64__
return (unsigned int)__builtin_ia32_crc32di(odd_constant,
return (unsigned int)__builtin_ia32_crc32di(fnv1a_32_seed,
(uint64_t)(uintptr_t)keyptr);
#else
const uint64_t key = (uint64_t)(uintptr_t)keyptr;
uint32_t crc;

crc = __builtin_ia32_crc32si(odd_constant, (uint32_t)(key & 0xffffffff));
crc = __builtin_ia32_crc32si(fnv1a_32_seed, (uint32_t)(key & 0xffffffff));
crc = __builtin_ia32_crc32si(crc, (uint32_t)(key >> 32));

return crc;
Expand All @@ -193,19 +210,20 @@ static inline unsigned int hash_int64_crc32(const void *keyptr)

#endif

uint64_t fnv1a_64_seed = 0xcbf29ce484222325ull;
uint32_t fnv1a_32_seed = 0x811c9dc5u;

__attribute__((constructor(65535))) static void initialize_odd_constant(void)
__attribute__((constructor(65535))) static void initialize_fnv1a_seed(void)
{
/* This constant is randomized in order to mitigate the DDoS attack
uint8_t entropy[128];

/* The seeds are randomized in order to mitigate the DDoS attack
* described by Crosby and Wallach in UsenixSec2003. */
if (lwan_getentropy(&odd_constant, sizeof(odd_constant), 0) < 0)
odd_constant = DEFAULT_ODD_CONSTANT;
odd_constant |= 1;
if (UNLIKELY(lwan_getentropy(entropy, sizeof(entropy), 0) < 0)) {
lwan_status_perror("Could not initialize FNV1a seed");
__builtin_unreachable();
}

fnv1a_64_seed = fnv1a_64(&odd_constant, sizeof(odd_constant));
fnv1a_32_seed = fnv1a_32(&odd_constant, sizeof(odd_constant));
fnv1a_64_seed = fnv1a_64(entropy, sizeof(entropy));
fnv1a_32_seed = fnv1a_32(entropy, sizeof(entropy));
lwan_always_bzero(entropy, sizeof(entropy));

#if defined(LWAN_HAVE_BUILTIN_CPU_INIT) && defined(LWAN_HAVE_BUILTIN_IA32_CRC32)
__builtin_cpu_init();
Expand Down

0 comments on commit 5472927

Please sign in to comment.