summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Mraz <tomas@openssl.org>2024-05-27 16:49:15 +0200
committerTomas Mraz <tomas@openssl.org>2024-08-21 15:21:25 +0200
commit71fe7f09831682e0dafe49e927da195792cff385 (patch)
tree44774f5cbc2cc4b7bc249a1b595855f4319e66c3
parenthashtable.c: Avoid infinite loop in ossl_ht_insert() (diff)
downloadopenssl-71fe7f09831682e0dafe49e927da195792cff385.tar.xz
openssl-71fe7f09831682e0dafe49e927da195792cff385.zip
hashtable: Support lockless reads
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)
-rw-r--r--crypto/hashtable/build.info6
-rw-r--r--crypto/hashtable/hashtable.c13
-rw-r--r--doc/internal/man3/ossl_ht_new.pod11
-rw-r--r--fuzz/hashtable.c2
-rw-r--r--include/internal/hashtable.h5
-rw-r--r--providers/fips/fipsprov.c6
-rw-r--r--test/lhash_test.c6
7 files changed, 33 insertions, 16 deletions
diff --git a/crypto/hashtable/build.info b/crypto/hashtable/build.info
index 72d84f13d9..514fcff6cf 100644
--- a/crypto/hashtable/build.info
+++ b/crypto/hashtable/build.info
@@ -1,4 +1,6 @@
LIBS=../../libcrypto
-SOURCE[../../libcrypto]=\
- hashtable.c
+$COMMON=hashtable.c
+
+SOURCE[../../libcrypto]=$COMMON
+SOURCE[../../providers/libfips.a]=$COMMON
diff --git a/crypto/hashtable/hashtable.c b/crypto/hashtable/hashtable.c
index b47d6938b9..0890db0cec 100644
--- a/crypto/hashtable/hashtable.c
+++ b/crypto/hashtable/hashtable.c
@@ -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;
}
-
diff --git a/doc/internal/man3/ossl_ht_new.pod b/doc/internal/man3/ossl_ht_new.pod
index a7601d1e91..18aa5d1e4d 100644
--- a/doc/internal/man3/ossl_ht_new.pod
+++ b/doc/internal/man3/ossl_ht_new.pod
@@ -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>
diff --git a/fuzz/hashtable.c b/fuzz/hashtable.c
index 9d911d86c2..b131d16bcc 100644
--- a/fuzz/hashtable.c
+++ b/fuzz/hashtable.c
@@ -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();
diff --git a/include/internal/hashtable.h b/include/internal/hashtable.h
index e486397ae9..5ca1efbe22 100644
--- a/include/internal/hashtable.h
+++ b/include/internal/hashtable.h
@@ -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
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index 0081088fb9..5a016f70c0 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -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;
diff --git a/test/lhash_test.c b/test/lhash_test.c
index d3e929e2e0..e0da12270e 100644
--- a/test/lhash_test.c
+++ b/test/lhash_test.c
@@ -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];