]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
hashtable: Support lockless reads
authorTomas Mraz <tomas@openssl.org>
Mon, 27 May 2024 14:49:15 +0000 (16:49 +0200)
committerTomas Mraz <tomas@openssl.org>
Wed, 21 Aug 2024 13:21:25 +0000 (15:21 +0200)
Also build it in the FIPS provider too and properly
report error on insert when hashtable cannot be grown.

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/24504)

crypto/hashtable/build.info
crypto/hashtable/hashtable.c
doc/internal/man3/ossl_ht_new.pod
fuzz/hashtable.c
include/internal/hashtable.h
providers/fips/fipsprov.c
test/lhash_test.c

index 72d84f13d958cffa7731242a49ea2d68306db0a2..514fcff6cf1787a286e26966aad79bc20b061898 100644 (file)
@@ -1,4 +1,6 @@
 LIBS=../../libcrypto
-SOURCE[../../libcrypto]=\
-        hashtable.c
+$COMMON=hashtable.c
+
+SOURCE[../../libcrypto]=$COMMON
+SOURCE[../../providers/libfips.a]=$COMMON
 
index b47d6938b903c856583b4dc54b20c84c5167bae6..0890db0cec16351dee439e78e4f719c4b30d0e2b 100644 (file)
@@ -179,7 +179,7 @@ static void internal_free_nop(HT_VALUE *v)
     return;
 }
 
-HT *ossl_ht_new(HT_CONFIG *conf)
+HT *ossl_ht_new(const HT_CONFIG *conf)
 {
     HT *new = OPENSSL_zalloc(sizeof(*new));
 
@@ -427,7 +427,7 @@ static void free_old_neigh_table(void *arg)
  */
 static int grow_hashtable(HT *h, size_t oldsize)
 {
-    struct ht_mutable_data_st *newmd = OPENSSL_zalloc(sizeof(*newmd));
+    struct ht_mutable_data_st *newmd;
     struct ht_mutable_data_st *oldmd = ossl_rcu_deref(&h->md);
     int rc = 0;
     uint64_t oldi, oldj, newi, newj;
@@ -436,7 +436,10 @@ static int grow_hashtable(HT *h, size_t oldsize)
     int rehashed;
     size_t newsize = oldsize * 2;
 
-    if (newmd == NULL)
+    if (h->config.lockless_reads)
+        goto out;
+
+    if ((newmd = OPENSSL_zalloc(sizeof(*newmd))) == NULL)
         goto out;
 
     /* bucket list is always a power of 2 */
@@ -700,6 +703,9 @@ int ossl_ht_delete(HT *h, HT_KEY *key)
     HT_VALUE *nv = NULL;
     int rc = 0;
 
+    if (h->config.lockless_reads)
+        return 0;
+
     hash = h->config.ht_hash_fn(key->keybuf, key->keysize);
 
     neigh_idx = hash & h->md->neighborhood_mask;
@@ -724,4 +730,3 @@ int ossl_ht_delete(HT *h, HT_KEY *key)
     }
     return rc;
 }
-
index a7601d1e914fd74f1ad02d90ed11efb1babc3fdd..18aa5d1e4d343545fa3e657f30f1b636edbc4aeb 100644 (file)
@@ -20,7 +20,7 @@ IMPLEMENT_HT_VALUE_TYPE_FNS
 
 =head1 SYNOPSIS
 
- HT *ossl_ht_new(HT_CONFIG *conf);
+ HT *ossl_ht_new(const HT_CONFIG *conf);
  void ossl_ht_free(HT *htable);
  void ossl_ht_read_lock(HT *htable);
  void ossl_ht_read_unlock(HT *htable);
@@ -66,14 +66,14 @@ contains configurations options for hashtable.  Current config options consist
 of:
     I<ht_free_fn> The function to call to free a value, may be NULL.
     I<ht_hash_fn> The function to generate a hash value for a key, may be NULL.
-    I<init_neighborhood_len> The initial number of neighborhoods in the hash table.
+    I<init_neighborhoods> The initial number of neighborhoods in the hash table.
 
 Note that init_bucket_len may be set to zero, which will use the default initial
 bucket size, which will be automatically expanded with the hash table load
 average reaches 0.75.
 
-Note that lockless_read operation implies behavioral restrictions.  Specifically
-    Only element additions are allowed, deletion operations will fail
+Note that lockless_read operation implies behavioral restrictions. Specifically
+only element additions are allowed, deletion operations will fail
     Hash table growth is inhibited.  init_bucket_len should be set to an
     appropriate value to prevent performance degradation
     The table owner is responsible for ensuring there are no readers during a
@@ -281,6 +281,9 @@ provided filter
 ossl_ht_get() returns an B<HT_VALUE> pointer, or NULL if the element was not
 found.
 
+ossl_ht_insert() returns 1 if an element was inserted, 0 if the element is
+already present, -1 on fatal errors (memory allocation or growth not allowed).
+
 =head1 EXAMPLES
 
 #include <stdio.h>
index 9d911d86c29093c93d3207406c9e520e17ae17da..b131d16bcc1a8512221aa0132f5657ed131122cd 100644 (file)
@@ -99,7 +99,7 @@ static void fuzz_free_cb(HT_VALUE *v)
 
 int FuzzerInitialize(int *argc, char ***argv)
 {
-    HT_CONFIG fuzz_conf = {NULL, fuzz_free_cb, NULL, 1, 0};
+    HT_CONFIG fuzz_conf = {NULL, fuzz_free_cb, NULL, 0, 1};
 
     OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
     ERR_clear_error();
index e486397ae9f4512c061e4d9ae333284ea9aa1982..5ca1efbe22276180a3b1ee944626b6e5e1bd6d5d 100644 (file)
@@ -51,8 +51,9 @@ typedef struct ht_config_st {
     OSSL_LIB_CTX *ctx;
     void (*ht_free_fn)(HT_VALUE *obj);
     uint64_t (*ht_hash_fn)(uint8_t *key, size_t keylen);
+    size_t init_neighborhoods;
     uint32_t collision_check;
-    uint32_t init_neighborhoods;
+    uint32_t lockless_reads;
 } HT_CONFIG;
 
 /*
@@ -249,7 +250,7 @@ static void ossl_unused ossl_ht_strcase(char *tgt, const char *src, int len)
 /*
  * Create a new hashtable
  */
-HT *ossl_ht_new(HT_CONFIG *conf);
+HT *ossl_ht_new(const HT_CONFIG *conf);
 
 /*
  * Frees a hash table, potentially freeing all elements
index 0081088fb98df76e3147c0d876b89c4b372aae07..5a016f70c021884a878269775e427c9c9a741525 100644 (file)
@@ -1134,6 +1134,12 @@ int CRYPTO_secure_allocated(const void *ptr)
     return c_CRYPTO_secure_allocated(ptr);
 }
 
+void *CRYPTO_aligned_alloc(size_t num, size_t align, void **freeptr,
+                           const char *file, int line)
+{
+    return NULL;
+}
+
 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
 {
     va_list args;
index d3e929e2e06f0fc0ec108d017cf61d74298bdd72..e0da12270e6bc902361dd632b3c73602bd850ceb 100644 (file)
@@ -230,8 +230,8 @@ static int test_int_hashtable(void)
         NULL,
         NULL,
         NULL,
-        1,
         0,
+        1,
     };
     INTKEY key;
     int rc = 0;
@@ -408,8 +408,8 @@ static int test_hashtable_stress(void)
         NULL,              /* use default context */
         hashtable_intfree, /* our free function */
         hashtable_hash,    /* our hash function */
-        1,                 /* Check collisions */
         625000,            /* preset hash size */
+        1,                 /* Check collisions */
     };
     HT *h;
     INTKEY key;
@@ -627,8 +627,8 @@ static int test_hashtable_multithread(void)
         NULL,              /* use default context */
         hashtable_mt_free, /* our free function */
         NULL,              /* default hash function */
-        1,                 /* Check collisions */
         0,                 /* default hash size */
+        1,                 /* Check collisions */
     };
     int ret = 0;
     thread_t workers[4];