Skip to content

Commit

Permalink
Data Race fix when using callbacks with multiple threads
Browse files Browse the repository at this point in the history
  • Loading branch information
msi-debian authored and msi-debian committed Dec 18, 2024
1 parent 5e13fc2 commit 7ff2ac2
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 1 deletion.
101 changes: 100 additions & 1 deletion wolfcrypt/src/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,14 +296,113 @@ This library contains implementation for the random number generator.

static wc_RngSeed_Cb seedCb = NULL;

#if defined(SINGLE_THREADED) || !defined(WC_MULTI_THREADED_CALLBACKS)

/* Will cause data race if multiple threads want to use their own callback */
/* Since it is setting a function Pointer Mutex will not resolve the issue */
int wc_SetSeed_Cb(wc_RngSeed_Cb cb)
{
seedCb = cb;
return 0;
}

#endif
#else /* Solution only works with POSIX library */

/* Use to determine if we are setting a call back */
wolfSSL_Mutex seedCbMutex;

static pthread_key_t seedCbKey; /* Key to determine if a cb is being set */


/* Code allocates a linked list based on thread potentially */
/* Use mutex for copying */
int wc_SetSeed_Cb(wc_RngSeed_Cb cb)
{
int ret;
static int initCb = 0; /* So threads cannot pass until callback is set */

if (seedCb == NULL) {/* Only need this once to set seedCb to generic func */
/* Setup so the mutex should only happen once for the first setup */
/* This way locking doesn't constantly happen, but also prevents */
/* threads from escaping and using a null seedCb on initial startup */
ret = wc_LockMutex(&seedCbMutex);
if (ret != 0) {
return ret;
}
if (seedCb == NULL) {
initCb = 0; /* Reset if CB is NULL */
}
if (!initCb) {
seedCb = (wc_RngSeed_Cb)multiThreadedSeedCb; /* Use global */
ret = createCbKey(&seedCbKey, NULL);
if (ret != 0) {
return ret;
}
initCb = 1;
}
ret = wc_UnLockMutex(&seedCbMutex);
if (ret != 0) {
return ret;
}
}

ret = setCbKey(&seedCbKey, cb);
return ret;
}

/* Function to allow each thread to have an independant callback */

Check failure on line 353 in wolfcrypt/src/random.c

View workflow job for this annotation

GitHub Actions / codespell

independant ==> independent
int multiThreadedSeedCb(OS_Seed* os, byte* output, word32 sz)
{
int ret = 0;
wc_RngSeed_Cb threadCb = (wc_RngSeed_Cb)pthread_getspecific(seedCbKey);
if (threadCb == NULL) {
/* If key does not exist(due to seedCb not being set in thread) */
/* We need to assume default CB is wc_GenerateSeed until */
/* wc_SetSeed_Cb is called with the desired cb function for the */
/* thread to use */
ret = wc_SetSeed_Cb(wc_GenerateSeed);
if (ret != 0) {
return ret;
}
threadCb = (wc_RngSeed_Cb)pthread_getspecific(seedCbKey);
if (threadCb == NULL) { /* Should not be NULL*/
return MISSING_RNG_E;
}
}
ret = threadCb(os, output, sz);
return ret;
}


/* Set the thread-specific key to callback function for thread */
int setCbKey(pthread_key_t* key, void* cb)
{
int ret = 0;

if (key == NULL || cb == NULL) {
return BAD_FUNC_ARG;
}

/* Set callback directly */
ret = pthread_setspecific(*key, cb);
return ret;
}

/* Should only be called once will setup key for all threads to use */
int createCbKey(pthread_key_t* key, void* destructor)
{
printf("Call Back Key Created\n");
if (key == NULL) { /* destructor can be NULL */
return BAD_FUNC_ARG;
}
if (pthread_key_create(key, destructor) != 0) {
return MEMORY_E;
}
return 0;
}

#endif /* defined(SINGLE_THREADED) || !defined(WC_MULTI_THREADED_CALLBACKS) */
#endif /* WC_RNG_SEED_CB */

/* Internal return codes */
#define DRBG_SUCCESS 0
Expand Down
14 changes: 14 additions & 0 deletions wolfssl/wolfcrypt/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,20 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng);

#ifdef WC_RNG_SEED_CB
WOLFSSL_API int wc_SetSeed_Cb(wc_RngSeed_Cb cb);

#ifdef WC_MULTI_THREADED_CALLBACKS
#ifndef WOLFSSL_PTHREADS
#error Only Supported with POSIX Threads
#endif

/* Multi-threaded seed callback for each thread */
WOLFSSL_LOCAL int multiThreadedSeedCb(OS_Seed* os, byte* output, word32 sz);

/* Set and Create functions */
WOLFSSL_LOCAL int setCbKey(pthread_key_t* key, void* value);
WOLFSSL_LOCAL int createCbKey(pthread_key_t* key, void* destructor);

#endif
#endif

#ifdef HAVE_HASHDRBG
Expand Down

0 comments on commit 7ff2ac2

Please sign in to comment.