diff options
author | Tomas Mraz <tomas@openssl.org> | 2024-05-27 16:49:15 +0200 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2024-08-21 15:21:25 +0200 |
commit | 71fe7f09831682e0dafe49e927da195792cff385 (patch) | |
tree | 44774f5cbc2cc4b7bc249a1b595855f4319e66c3 | |
parent | hashtable.c: Avoid infinite loop in ossl_ht_insert() (diff) | |
download | openssl-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.info | 6 | ||||
-rw-r--r-- | crypto/hashtable/hashtable.c | 13 | ||||
-rw-r--r-- | doc/internal/man3/ossl_ht_new.pod | 11 | ||||
-rw-r--r-- | fuzz/hashtable.c | 2 | ||||
-rw-r--r-- | include/internal/hashtable.h | 5 | ||||
-rw-r--r-- | providers/fips/fipsprov.c | 6 | ||||
-rw-r--r-- | test/lhash_test.c | 6 |
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]; |