diff --git a/configure.ac b/configure.ac index 34cdc003..2253d0d8 100644 --- a/configure.ac +++ b/configure.ac @@ -644,7 +644,7 @@ dnl Checks for functions and headers AS_IF([test "x$EMSCRIPTEN" = "x"],[ AC_CHECK_FUNCS([arc4random arc4random_buf]) - AC_CHECK_FUNCS([mmap mlock madvise mprotect explicit_bzero]) + AC_CHECK_FUNCS([mmap mlock madvise mprotect explicit_bzero nanosleep]) ]) AC_CHECK_FUNCS([posix_memalign getpid]) diff --git a/src/libsodium/sodium/core.c b/src/libsodium/sodium/core.c index 31631f6d..c090ca96 100644 --- a/src/libsodium/sodium/core.c +++ b/src/libsodium/sodium/core.c @@ -1,4 +1,12 @@ +#include +#include +#ifdef HAVE_PTHREAD +# include +#elif defined(_WIN32) +# include +#endif + #include "core.h" #include "crypto_generichash.h" #include "crypto_onetimeauth.h" @@ -18,12 +26,21 @@ # warning Alternatively, use the "stable" branch in the git repository. #endif -static int initialized; +static int _sodium_crit_enter(void); +static int _sodium_crit_leave(void); + +static volatile int initialized; int sodium_init(void) { + if (_sodium_crit_enter() != 0) { + return -1; + } if (initialized != 0) { + if (_sodium_crit_leave() != 0) { + return -1; + } return 1; } _sodium_runtime_get_cpu_features(); @@ -35,6 +52,105 @@ sodium_init(void) _crypto_scalarmult_curve25519_pick_best_implementation(); _crypto_stream_chacha20_pick_best_implementation(); initialized = 1; + if (_sodium_crit_leave() != 0) { + return -1; + } + return 0; +} + +#ifdef HAVE_PTHREAD + +static pthread_mutex_t _sodium_lock = PTHREAD_MUTEX_INITIALIZER; + +static int +_sodium_crit_enter(void) +{ + return pthread_mutex_lock(&_sodium_lock); +} + +static int +_sodium_crit_leave(void) +{ + return pthread_mutex_unlock(&_sodium_lock); +} + +#elif defined(_WIN32) + +static CRITICAL_SECTION *_sodium_lock; +static volatile LONG _sodium_lock_initialized; + +static int +_sodium_crit_enter(void) +{ + if (InterlockedCompareExchange(&_sodium_lock_initialized, + 1L, 0L) != 0L) { + InitializeCriticalSection(_sodium_lock); + InterlockedIncrement(&_sodium_lock_initialized); + } else { + while (InterlockedCompareExchange(&_sodium_lock_initialized, + 2L, 2L) != 2L) { + Sleep(0); + } + } + return 0; +} + +static int +_sodium_crit_leave(void) +{ + if (_sodium_lock == NULL) { + return -1; + } + LeaveCriticalSection(_sodium_lock); return 0; } + +#elif defined(__GNUC__) && !defined(__EMSCRIPTEN__) + +static volatile int _sodium_lock; + +static int +_sodium_crit_enter(void) +{ + if (__sync_lock_test_and_set(&_sodium_lock, 1) != 0) { + for (;;) { + if (_sodium_lock == 0U && + __sync_lock_test_and_set(&_sodium_lock, 1) == 0) { + break; + } +# ifdef HAVE_NANOSLEEP + { + struct timespec q; + memset(&q, 0, sizeof q); + (void) nanosleep(&q, NULL); + } +# endif + } + } + return 0; +} + +static int +_sodium_crit_leave(void) +{ + __sync_lock_release(&_sodium_lock); + + return 0; +} + +#else + +static int +_sodium_crit_enter(void) +{ + return 0; +} + +static int +_sodium_crit_leave(void) +{ + return 0; +} + +#endif diff --git a/src/libsodium/sodium/utils.c b/src/libsodium/sodium/utils.c index bb2513bf..b2c99325 100644 --- a/src/libsodium/sodium/utils.c +++ b/src/libsodium/sodium/utils.c @@ -14,8 +14,6 @@ # include #endif -#include "utils.h" -#include "randombytes.h" #ifdef _WIN32 # include # include @@ -23,6 +21,9 @@ # include #endif +#include "utils.h" +#include "randombytes.h" + #ifndef ENOSYS # define ENOSYS ENXIO #endif