mirror of
https://github.com/openssl/openssl.git
synced 2026-10-28 16:36:02 +08:00
Our CRYPTO atomic api has a somewhat consistent problem in that its possible in the case where locking fails to return an error while the actual operation (store_int, store_ptr, etc), actually succeded. cmp_exch is somewhat special here in that we may really need to know independently if the function failed due to lock failure and if the exchange occured (so we can know the output value of *expect). Add a separate parameter to allow callers to be informed of these statuses independently. Reviewed-by: Norbert Pocs <norbertp@openssl.org> Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org> MergeDate: Tue Jun 9 17:46:07 2026 (Merged from https://github.com/openssl/openssl/pull/31319)
332 lines
6.1 KiB
C
332 lines
6.1 KiB
C
/*
|
|
* Copyright 2016-2026 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <openssl/crypto.h>
|
|
#include "internal/cryptlib.h"
|
|
#include "internal/rcu.h"
|
|
#include "rcu_internal.h"
|
|
|
|
#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
|
|
|
|
#if defined(OPENSSL_SYS_UNIX)
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
struct rcu_lock_st {
|
|
struct rcu_cb_item *cb_items;
|
|
};
|
|
|
|
CRYPTO_RCU_LOCK *ossl_rcu_lock_new(int num_writers,
|
|
ossl_unused OSSL_LIB_CTX *ctx)
|
|
{
|
|
struct rcu_lock_st *lock;
|
|
|
|
lock = OPENSSL_zalloc(sizeof(*lock));
|
|
return lock;
|
|
}
|
|
|
|
void ossl_rcu_lock_free(CRYPTO_RCU_LOCK *lock)
|
|
{
|
|
OPENSSL_free(lock);
|
|
}
|
|
|
|
int ossl_rcu_read_lock(CRYPTO_RCU_LOCK *lock)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void ossl_rcu_write_lock(CRYPTO_RCU_LOCK *lock)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void ossl_rcu_write_unlock(CRYPTO_RCU_LOCK *lock)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void ossl_rcu_read_unlock(CRYPTO_RCU_LOCK *lock)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock)
|
|
{
|
|
struct rcu_cb_item *items = lock->cb_items;
|
|
struct rcu_cb_item *tmp;
|
|
|
|
lock->cb_items = NULL;
|
|
|
|
while (items != NULL) {
|
|
tmp = items->next;
|
|
items->fn(items->data);
|
|
OPENSSL_free(items);
|
|
items = tmp;
|
|
}
|
|
}
|
|
|
|
CRYPTO_RCU_CB_ITEM *ossl_rcu_cb_item_new(void)
|
|
{
|
|
return OPENSSL_zalloc(sizeof(CRYPTO_RCU_CB_ITEM));
|
|
}
|
|
|
|
void ossl_rcu_cb_item_free(CRYPTO_RCU_CB_ITEM *item)
|
|
{
|
|
OPENSSL_free(item);
|
|
}
|
|
|
|
void ossl_rcu_call(CRYPTO_RCU_LOCK *lock, CRYPTO_RCU_CB_ITEM *item,
|
|
rcu_cb_fn cb, void *data)
|
|
{
|
|
item->fn = cb;
|
|
item->data = data;
|
|
item->next = lock->cb_items;
|
|
lock->cb_items = item;
|
|
}
|
|
|
|
void *ossl_rcu_uptr_deref(void **p)
|
|
{
|
|
return (void *)*p;
|
|
}
|
|
|
|
void ossl_rcu_assign_uptr(void **p, void **v)
|
|
{
|
|
*(void **)p = *(void **)v;
|
|
}
|
|
|
|
CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
|
|
{
|
|
CRYPTO_RWLOCK *lock;
|
|
|
|
if ((lock = CRYPTO_zalloc(sizeof(unsigned int), NULL, 0)) == NULL)
|
|
/* Don't set error, to avoid recursion blowup. */
|
|
return NULL;
|
|
|
|
*(unsigned int *)lock = 1;
|
|
|
|
return lock;
|
|
}
|
|
|
|
__owur int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
|
|
{
|
|
if (!ossl_assert(*(unsigned int *)lock == 1))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
__owur int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
|
|
{
|
|
if (!ossl_assert(*(unsigned int *)lock == 1))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
|
|
{
|
|
if (!ossl_assert(*(unsigned int *)lock == 1))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
|
|
{
|
|
if (lock == NULL)
|
|
return;
|
|
|
|
*(unsigned int *)lock = 0;
|
|
OPENSSL_free(lock);
|
|
|
|
return;
|
|
}
|
|
|
|
int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
|
|
{
|
|
if (*once != 0)
|
|
return 1;
|
|
|
|
init();
|
|
*once = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX 256
|
|
|
|
struct thread_local_storage_entry {
|
|
void *data;
|
|
uint8_t used;
|
|
};
|
|
|
|
static struct thread_local_storage_entry thread_local_storage[OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX];
|
|
|
|
int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
|
|
{
|
|
int entry_idx = 0;
|
|
|
|
for (entry_idx = 0; entry_idx < OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX; entry_idx++) {
|
|
if (!thread_local_storage[entry_idx].used)
|
|
break;
|
|
}
|
|
|
|
if (entry_idx == OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
|
|
return 0;
|
|
|
|
*key = entry_idx;
|
|
thread_local_storage[*key].used = 1;
|
|
thread_local_storage[*key].data = NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
|
|
{
|
|
if (*key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
|
|
return NULL;
|
|
|
|
return thread_local_storage[*key].data;
|
|
}
|
|
|
|
int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
|
|
{
|
|
if (*key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
|
|
return 0;
|
|
|
|
thread_local_storage[*key].data = val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
|
|
{
|
|
if (*key >= OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX)
|
|
return 0;
|
|
|
|
thread_local_storage[*key].used = 0;
|
|
thread_local_storage[*key].data = NULL;
|
|
*key = OPENSSL_CRYPTO_THREAD_LOCAL_KEY_MAX + 1;
|
|
return 1;
|
|
}
|
|
|
|
CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
|
|
{
|
|
return (a == b);
|
|
}
|
|
|
|
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
|
|
{
|
|
*val += amount;
|
|
*ret = *val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret,
|
|
CRYPTO_RWLOCK *lock)
|
|
{
|
|
*val += op;
|
|
*ret = *val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret,
|
|
CRYPTO_RWLOCK *lock)
|
|
{
|
|
*val &= op;
|
|
*ret = *val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
|
|
CRYPTO_RWLOCK *lock)
|
|
{
|
|
*val |= op;
|
|
*ret = *val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
|
|
{
|
|
*ret = *val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock)
|
|
{
|
|
*dst = val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock)
|
|
{
|
|
*ret = *val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock)
|
|
{
|
|
*dst = val;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_load_ptr(void **ptr, void **ret, CRYPTO_RWLOCK *lock)
|
|
{
|
|
*ret = *ptr;
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_store_ptr(void **dst, void **val, CRYPTO_RWLOCK *lock)
|
|
{
|
|
*dst = *val;
|
|
return 1;
|
|
}
|
|
|
|
int CRYPTO_atomic_cmp_exch_ptr(void **ptr, void **expect, void *desire, CRYPTO_RWLOCK *lock, int *lock_failed)
|
|
{
|
|
int lock_sink;
|
|
|
|
if (lock_failed == NULL)
|
|
lock_failed = &lock_sink;
|
|
|
|
*lock_failed = 0;
|
|
if (*ptr == *expect) {
|
|
*ptr = desire;
|
|
return 1;
|
|
}
|
|
*expect = *ptr;
|
|
return 0;
|
|
}
|
|
|
|
int openssl_init_fork_handlers(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int openssl_get_fork_id(void)
|
|
{
|
|
#if defined(OPENSSL_SYS_UNIX)
|
|
return getpid();
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
#endif
|