From 57cfd221a67fc1ad378ec100cbf0d944e6049c7a Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 1 Sep 2023 14:52:04 +0200 Subject: [PATCH] dict: Use xoroshiro64** as PRNG Stop using rand_r. This enables hash randomization on all platforms. --- CMakeLists.txt | 1 - config.h.cmake.in | 3 -- configure.ac | 2 +- dict.c | 111 ++++++++++++++++++++++------------------- hash.c | 14 ++---- include/private/dict.h | 10 ++-- parser.c | 2 +- 7 files changed, 72 insertions(+), 71 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9eb786d4..5af5e6d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,6 @@ if (NOT MSVC) check_include_files(netdb.h HAVE_NETDB_H) check_include_files(netinet/in.h HAVE_NETINET_IN_H) check_include_files(poll.h HAVE_POLL_H) - check_function_exists(rand_r HAVE_RAND_R) check_library_exists(dld shl_load "" HAVE_SHLLOAD) check_function_exists(stat HAVE_STAT) check_include_files(stdint.h HAVE_STDINT_H) diff --git a/config.h.cmake.in b/config.h.cmake.in index 0d8c341f..8fd47dea 100644 --- a/config.h.cmake.in +++ b/config.h.cmake.in @@ -60,9 +60,6 @@ /* Define if is there */ #cmakedefine HAVE_PTHREAD_H 1 -/* Define to 1 if you have the `rand_r' function. */ -#cmakedefine HAVE_RAND_R 1 - /* Have shl_load based dso */ #cmakedefine HAVE_SHLLOAD 1 diff --git a/configure.ac b/configure.ac index b8646cf1..10ffe328 100644 --- a/configure.ac +++ b/configure.ac @@ -307,7 +307,7 @@ dnl AC_CHECK_FUNCS(snprintf vsnprintf,, NEED_TRIO=1) dnl Checks for library functions. -AC_CHECK_FUNCS([gettimeofday ftime stat rand_r isascii mmap munmap]) +AC_CHECK_FUNCS([gettimeofday ftime stat isascii mmap munmap]) AH_VERBATIM([HAVE_MUNMAP_AFTER],[/* mmap() is no good without munmap() */ #if defined(HAVE_MMAP) && !defined(HAVE_MUNMAP) diff --git a/dict.c b/dict.c index 4b3cfc95..7a6f960f 100644 --- a/dict.c +++ b/dict.c @@ -20,12 +20,24 @@ #include "libxml.h" #include -#include +#include #include #include "private/dict.h" #include "private/threads.h" +#ifdef HAVE_STDINT_H +#include +#elif defined(_WIN32) +typedef unsigned __int32 uint32_t; +#endif + +#include +#include +#include +#include +#include + /* * Following http://www.ocert.org/advisories/ocert-2011-003.html * it seems that having hash randomization might be a good idea @@ -41,22 +53,6 @@ #define DICT_RANDOMIZATION #endif -#include -#ifdef HAVE_STDINT_H -#include -#else -#ifdef HAVE_INTTYPES_H -#include -#elif defined(_WIN32) -typedef unsigned __int32 uint32_t; -#endif -#endif -#include -#include -#include -#include -#include - /* #define DEBUG_GROW */ /* #define DICT_DEBUG_PATTERNS */ @@ -122,7 +118,7 @@ struct _xmlDict { struct _xmlDict *subdict; /* used for randomization */ - int seed; + unsigned seed; /* used to impose a limit on size */ size_t limit; }; @@ -133,59 +129,72 @@ struct _xmlDict { */ static xmlMutex xmlDictMutex; -#ifdef DICT_RANDOMIZATION -#ifdef HAVE_RAND_R /* * Internal data for random function, protected by xmlDictMutex */ -static unsigned int rand_seed = 0; -#endif -#endif +static uint32_t rand_seed[2]; /** * xmlInitializeDict: * * DEPRECATED: Alias for xmlInitParser. */ -int xmlInitializeDict(void) { +int +xmlInitializeDict(void) { xmlInitParser(); return(0); } /** - * __xmlInitializeDict: + * xmlInitializeDict: * - * This function is not public - * Do the dictionary mutex initialization. + * Initialize mutex and global PRNG seed. */ -int __xmlInitializeDict(void) { +#ifdef __clang__ +ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") +ATTRIBUTE_NO_SANITIZE("unsigned-shift-base") +#endif +void +xmlInitDictInternal(void) { + int var; + xmlInitMutex(&xmlDictMutex); -#ifdef DICT_RANDOMIZATION -#ifdef HAVE_RAND_R - rand_seed = time(NULL); - rand_r(& rand_seed); -#else - srand(time(NULL)); -#endif -#endif - return(1); + /* TODO: Get seed values from system PRNG */ + + rand_seed[0] = (uint32_t) time(NULL) ^ + HASH_ROL((uint32_t) (size_t) &xmlInitializeDict, 8); + rand_seed[1] = HASH_ROL((uint32_t) (size_t) &xmlDictMutex, 16) ^ + HASH_ROL((uint32_t) (size_t) &var, 24); } -#ifdef DICT_RANDOMIZATION -int __xmlRandom(void) { - int ret; +#ifdef __clang__ +ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") +ATTRIBUTE_NO_SANITIZE("unsigned-shift-base") +#endif +static uint32_t +xoroshiro64ss(uint32_t *s) { + uint32_t s0 = s[0]; + uint32_t s1 = s[1]; + uint32_t result = HASH_ROL(s0 * 0x9E3779BB, 5) * 5; + + s1 ^= s0; + s[0] = HASH_ROL(s0, 26) ^ s1 ^ (s1 << 9); + s[1] = HASH_ROL(s1, 13); + + return result; +} + +unsigned +xmlRandom(void) { + uint32_t ret; xmlMutexLock(&xmlDictMutex); -#ifdef HAVE_RAND_R - ret = rand_r(& rand_seed); -#else - ret = rand(); -#endif + ret = xoroshiro64ss(rand_seed); xmlMutexUnlock(&xmlDictMutex); + return(ret); } -#endif /** * xmlDictCleanup: @@ -358,7 +367,7 @@ ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") ATTRIBUTE_NO_SANITIZE("unsigned-shift-base") #endif static uint32_t -xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) { +xmlDictComputeBigKey(const xmlChar* data, int namelen, unsigned seed) { uint32_t hash; int i; @@ -395,7 +404,7 @@ ATTRIBUTE_NO_SANITIZE("unsigned-shift-base") #endif static unsigned long xmlDictComputeBigQKey(const xmlChar *prefix, int plen, - const xmlChar *name, int len, int seed) + const xmlChar *name, int len, unsigned seed) { uint32_t hash; int i; @@ -431,7 +440,7 @@ xmlDictComputeBigQKey(const xmlChar *prefix, int plen, * for low hash table fill. */ static unsigned long -xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) { +xmlDictComputeFastKey(const xmlChar *name, int namelen, unsigned seed) { unsigned long value = seed; if ((name == NULL) || (namelen <= 0)) @@ -476,7 +485,7 @@ xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) { */ static unsigned long xmlDictComputeFastQKey(const xmlChar *prefix, int plen, - const xmlChar *name, int len, int seed) + const xmlChar *name, int len, unsigned seed) { unsigned long value = seed; @@ -578,7 +587,7 @@ xmlDictCreate(void) { if (dict->dict) { memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry)); #ifdef DICT_RANDOMIZATION - dict->seed = __xmlRandom(); + dict->seed = xmlRandom(); #else dict->seed = 0; #endif diff --git a/hash.c b/hash.c index 0bc09031..175a8137 100644 --- a/hash.c +++ b/hash.c @@ -70,9 +70,7 @@ struct _xmlHashTable { int size; int nbElems; xmlDictPtr dict; -#ifdef HASH_RANDOMIZATION - int random_seed; -#endif + unsigned random_seed; }; /* @@ -86,12 +84,10 @@ ATTRIBUTE_NO_SANITIZE("unsigned-shift-base") static unsigned long xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, const xmlChar *name2, const xmlChar *name3) { - unsigned long value = 0L; + unsigned long value; unsigned long ch; -#ifdef HASH_RANDOMIZATION value = table->random_seed; -#endif if (name != NULL) { value += 30 * (*name); while ((ch = *name++) != 0) { @@ -122,12 +118,10 @@ xmlHashComputeQKey(xmlHashTablePtr table, const xmlChar *prefix, const xmlChar *name, const xmlChar *prefix2, const xmlChar *name2, const xmlChar *prefix3, const xmlChar *name3) { - unsigned long value = 0L; + unsigned long value; unsigned long ch; -#ifdef HASH_RANDOMIZATION value = table->random_seed; -#endif if (prefix != NULL) value += 30 * (*prefix); else @@ -197,7 +191,7 @@ xmlHashCreate(int size) { if (table->table) { memset(table->table, 0, size * sizeof(xmlHashEntry)); #ifdef HASH_RANDOMIZATION - table->random_seed = __xmlRandom(); + table->random_seed = xmlRandom(); #endif return(table); } diff --git a/include/private/dict.h b/include/private/dict.h index fcc10bac..e35cfb23 100644 --- a/include/private/dict.h +++ b/include/private/dict.h @@ -1,11 +1,13 @@ #ifndef XML_DICT_H_PRIVATE__ #define XML_DICT_H_PRIVATE__ -XML_HIDDEN int -__xmlInitializeDict(void); +#define HASH_ROL(x,n) ((x) << (n) | ((x) & 0xFFFFFFFF) >> (32 - (n))) + +XML_HIDDEN void +xmlInitDictInternal(void); XML_HIDDEN void xmlCleanupDictInternal(void); -XML_HIDDEN int -__xmlRandom(void); +XML_HIDDEN unsigned +xmlRandom(void); #endif /* XML_DICT_H_PRIVATE__ */ diff --git a/parser.c b/parser.c index d7635482..814411dc 100644 --- a/parser.c +++ b/parser.c @@ -13702,7 +13702,7 @@ xmlInitParser(void) { xmlInitThreadsInternal(); xmlInitGlobalsInternal(); xmlInitMemoryInternal(); - __xmlInitializeDict(); + xmlInitDictInternal(); xmlInitEncodingInternal(); xmlRegisterDefaultInputCallbacks(); #ifdef LIBXML_OUTPUT_ENABLED