Blame SOURCES/cyrus-imapd-3.0-CVE-2021-33582.patch

61e92a
diff --git a/imap/http_dav.c b/imap/http_dav.c
61e92a
index 91bbc28b6b..a6fa5c8345 100644
61e92a
--- a/imap/http_dav.c
61e92a
+++ b/imap/http_dav.c
61e92a
@@ -5494,7 +5494,7 @@ EXPORTED int meth_propfind(struct transaction_t *txn, void *params)
61e92a
     xmlDocPtr indoc = NULL, outdoc = NULL;
61e92a
     xmlNodePtr root, cur = NULL, props = NULL;
61e92a
     xmlNsPtr ns[NUM_NAMESPACE];
61e92a
-    struct hash_table ns_table = { 0, NULL, NULL };
61e92a
+    struct hash_table ns_table = HASH_TABLE_INITIALIZER;
61e92a
     struct propfind_ctx fctx;
61e92a
     struct propfind_entry_list *elist = NULL;
61e92a
 
61e92a
@@ -7900,7 +7900,7 @@ int meth_report(struct transaction_t *txn, void *params)
61e92a
     xmlNodePtr inroot = NULL, outroot = NULL, cur, prop = NULL, props = NULL;
61e92a
     const struct report_type_t *report = NULL;
61e92a
     xmlNsPtr ns[NUM_NAMESPACE];
61e92a
-    struct hash_table ns_table = { 0, NULL, NULL };
61e92a
+    struct hash_table ns_table = HASH_TABLE_INITIALIZER;
61e92a
     struct propfind_ctx fctx;
61e92a
     struct propfind_entry_list *elist = NULL;
61e92a
 
61e92a
diff --git a/lib/hash.c b/lib/hash.c
61e92a
index 9703142c3b..84f2e80d28 100644
61e92a
--- a/lib/hash.c
61e92a
+++ b/lib/hash.c
61e92a
@@ -43,10 +43,11 @@ EXPORTED hash_table *construct_hash_table(hash_table *table, size_t size, int us
61e92a
       assert(table);
61e92a
       assert(size);
61e92a
 
61e92a
-      table->size  = size;
61e92a
+      table->size = size;
61e92a
+      table->seed = rand(); /* might be zero, that's okay */
61e92a
 
61e92a
       /* Allocate the table -- different for using memory pools and not */
61e92a
-      if(use_mpool) {
61e92a
+      if (use_mpool) {
61e92a
           /* Allocate an initial memory pool for 32 byte keys + the hash table
61e92a
            * + the buckets themselves */
61e92a
           table->pool =
61e92a
@@ -72,7 +73,7 @@ EXPORTED hash_table *construct_hash_table(hash_table *table, size_t size, int us
61e92a
 
61e92a
 EXPORTED void *hash_insert(const char *key, void *data, hash_table *table)
61e92a
 {
61e92a
-      unsigned val = strhash(key) % table->size;
61e92a
+      unsigned val = strhash_seeded(table->seed, key) % table->size;
61e92a
       bucket *ptr, *newptr;
61e92a
       bucket **prev;
61e92a
 
61e92a
@@ -153,9 +154,14 @@ EXPORTED void *hash_insert(const char *key, void *data, hash_table *table)
61e92a
 
61e92a
 EXPORTED void *hash_lookup(const char *key, hash_table *table)
61e92a
 {
61e92a
-      unsigned val = strhash(key) % table->size;
61e92a
+      unsigned val;
61e92a
       bucket *ptr;
61e92a
 
61e92a
+      if (!table->size)
61e92a
+          return NULL;
61e92a
+
61e92a
+      val = strhash_seeded(table->seed, key) % table->size;
61e92a
+
61e92a
       if (!(table->table)[val])
61e92a
             return NULL;
61e92a
 
61e92a
@@ -178,8 +184,7 @@ EXPORTED void *hash_lookup(const char *key, hash_table *table)
61e92a
  * since it will leak memory until you get rid of the entire hash table */
61e92a
 EXPORTED void *hash_del(const char *key, hash_table *table)
61e92a
 {
61e92a
-      unsigned val = strhash(key) % table->size;
61e92a
-      void *data;
61e92a
+      unsigned val = strhash_seeded(table->seed, key) % table->size;
61e92a
       bucket *ptr, *last = NULL;
61e92a
 
61e92a
       if (!(table->table)[val])
61e92a
@@ -200,15 +205,10 @@ EXPORTED void *hash_del(const char *key, hash_table *table)
61e92a
           int cmpresult = strcmp(key, ptr->key);
61e92a
           if (!cmpresult)
61e92a
           {
61e92a
+              void *data = ptr->data;
61e92a
               if (last != NULL )
61e92a
               {
61e92a
-                  data = ptr -> data;
61e92a
                   last -> next = ptr -> next;
61e92a
-                  if(!table->pool) {
61e92a
-                      free(ptr->key);
61e92a
-                      free(ptr);
61e92a
-                  }
61e92a
-                  return data;
61e92a
               }
61e92a
 
61e92a
               /*
61e92a
@@ -221,15 +221,15 @@ EXPORTED void *hash_del(const char *key, hash_table *table)
61e92a
 
61e92a
               else
61e92a
               {
61e92a
-                  data = ptr->data;
61e92a
                   (table->table)[val] = ptr->next;
61e92a
-                  if(!table->pool) {
61e92a
-                      free(ptr->key);
61e92a
-                      free(ptr);
61e92a
-                  }
61e92a
-                  return data;
61e92a
               }
61e92a
-          } else if (cmpresult < 0) {
61e92a
+              if(!table->pool) {
61e92a
+                  free(ptr->key);
61e92a
+                  free(ptr);
61e92a
+              }
61e92a
+              return data;
61e92a
+          }
61e92a
+          if (cmpresult < 0) {
61e92a
               /* its not here! */
61e92a
               return NULL;
61e92a
           }
61e92a
diff --git a/lib/hash.h b/lib/hash.h
61e92a
index 8051ac1760..cfa7da1ffa 100644
61e92a
--- a/lib/hash.h
61e92a
+++ b/lib/hash.h
61e92a
@@ -3,10 +3,11 @@
61e92a
 #define HASH__H
61e92a
 
61e92a
 #include <stddef.h>           /* For size_t     */
61e92a
+#include <stdint.h>
61e92a
 #include "mpool.h"
61e92a
 #include "strarray.h"
61e92a
 
61e92a
-#define HASH_TABLE_INITIALIZER {0, NULL, NULL}
61e92a
+#define HASH_TABLE_INITIALIZER {0, 0, NULL, NULL}
61e92a
 
61e92a
 /*
61e92a
 ** A hash table consists of an array of these buckets.  Each bucket
61e92a
@@ -32,6 +33,7 @@ typedef struct bucket {
61e92a
 
61e92a
 typedef struct hash_table {
61e92a
     size_t size;
61e92a
+    uint32_t seed;
61e92a
     bucket **table;
61e92a
     struct mpool *pool;
61e92a
 } hash_table;
61e92a
diff --git a/lib/strhash.c b/lib/strhash.c
61e92a
index d7c1741d2a..1b3251db73 100644
61e92a
--- a/lib/strhash.c
61e92a
+++ b/lib/strhash.c
61e92a
@@ -42,17 +42,32 @@
61e92a
 
61e92a
 #include "config.h"
61e92a
 
61e92a
-EXPORTED unsigned strhash(const char *string)
61e92a
+#include "lib/strhash.h"
61e92a
+
61e92a
+/* The well-known djb2 algorithm (e.g. http://www.cse.yorku.ca/~oz/hash.html),
61e92a
+ * with the addition of an optional seed to limit predictability.
61e92a
+ *
61e92a
+ * XXX return type 'unsigned' for back-compat to previous version, but
61e92a
+ * XXX ought to be 'uint32_t'
61e92a
+ */
61e92a
+EXPORTED unsigned strhash_seeded_djb2(uint32_t seed, const char *string)
61e92a
 {
61e92a
-      unsigned ret_val = 0;
61e92a
-      int i;
61e92a
+    const unsigned char *ustr = (const unsigned char *) string;
61e92a
+    unsigned hash = 5381;
61e92a
+    int c;
61e92a
 
61e92a
-      while (*string)
61e92a
-      {
61e92a
-            i = (int) *string;
61e92a
-            ret_val ^= i;
61e92a
-            ret_val <<= 1;
61e92a
-            string ++;
61e92a
-      }
61e92a
-      return ret_val;
61e92a
+    if (seed) {
61e92a
+        /* treat the bytes of the seed as a prefix to the string */
61e92a
+        unsigned i;
61e92a
+        for (i = 0; i < sizeof seed; i++) {
61e92a
+            c = seed & 0xff;
61e92a
+            hash = ((hash << 5) + hash) ^ c;
61e92a
+            seed >>= 8;
61e92a
+        }
61e92a
+    }
61e92a
+
61e92a
+    while ((c = *ustr++))
61e92a
+        hash = ((hash << 5) + hash) ^ c;
61e92a
+
61e92a
+    return hash;
61e92a
 }
61e92a
diff --git a/lib/strhash.h b/lib/strhash.h
61e92a
index 34533fdffa..27339bb288 100644
61e92a
--- a/lib/strhash.h
61e92a
+++ b/lib/strhash.h
61e92a
@@ -41,7 +41,11 @@
61e92a
  */
61e92a
 
61e92a
 #ifndef _STRHASH_H_
61e92a
+#include <stdint.h>
61e92a
 
61e92a
-unsigned strhash(const char *string);
61e92a
+unsigned strhash_seeded_djb2(uint32_t seed, const char *string);
61e92a
+
61e92a
+#define strhash(in)             strhash_seeded_djb2((0),  (in))
61e92a
+#define strhash_seeded(sd, in)  strhash_seeded_djb2((sd), (in))
61e92a
 
61e92a
 #endif /* _STRHASH_H_ */