1 
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6 #ifdef _WIN32
7 # include <windows.h>
8 #elif defined(HAVE_PTHREAD)
9 # include <pthread.h>
10 #endif
11 
12 #include "core.h"
13 #include "crypto_generichash.h"
14 #include "crypto_onetimeauth.h"
15 #include "crypto_scalarmult.h"
16 #include "crypto_stream_chacha20.h"
17 #include "crypto_stream_salsa20.h"
18 #include "randombytes.h"
19 #include "runtime.h"
20 #include "utils.h"
21 #include "private/implementations.h"
22 #include "private/mutex.h"
23 
24 static volatile int initialized;
25 static volatile int locked;
26 
27 int
sodium_init(void)28 sodium_init(void)
29 {
30     if (sodium_crit_enter() != 0) {
31         return -1; /* LCOV_EXCL_LINE */
32     }
33     if (initialized != 0) {
34         if (sodium_crit_leave() != 0) {
35             return -1; /* LCOV_EXCL_LINE */
36         }
37         return 1;
38     }
39     _sodium_runtime_get_cpu_features();
40     randombytes_stir();
41     _sodium_alloc_init();
42     _crypto_pwhash_argon2_pick_best_implementation();
43     _crypto_generichash_blake2b_pick_best_implementation();
44     _crypto_onetimeauth_poly1305_pick_best_implementation();
45     _crypto_scalarmult_curve25519_pick_best_implementation();
46     _crypto_stream_chacha20_pick_best_implementation();
47     _crypto_stream_salsa20_pick_best_implementation();
48     initialized = 1;
49     if (sodium_crit_leave() != 0) {
50         return -1; /* LCOV_EXCL_LINE */
51     }
52     return 0;
53 }
54 
55 #ifdef _WIN32
56 
57 static CRITICAL_SECTION _sodium_lock;
58 static volatile LONG    _sodium_lock_initialized;
59 
60 int
_sodium_crit_init(void)61 _sodium_crit_init(void)
62 {
63     LONG status = 0L;
64 
65     while ((status = InterlockedCompareExchange(&_sodium_lock_initialized,
66                                                 1L, 0L)) == 1L) {
67         Sleep(0);
68     }
69 
70     switch (status) {
71     case 0L:
72         InitializeCriticalSection(&_sodium_lock);
73         return InterlockedExchange(&_sodium_lock_initialized, 2L) == 1L ? 0 : -1;
74     case 2L:
75         return 0;
76     default: /* should never be reached */
77         return -1;
78     }
79 }
80 
81 int
sodium_crit_enter(void)82 sodium_crit_enter(void)
83 {
84     if (_sodium_crit_init() != 0) {
85         return -1; /* LCOV_EXCL_LINE */
86     }
87     EnterCriticalSection(&_sodium_lock);
88     assert(locked == 0);
89     locked = 1;
90 
91     return 0;
92 }
93 
94 int
sodium_crit_leave(void)95 sodium_crit_leave(void)
96 {
97     if (locked == 0) {
98 # ifdef EPERM
99         errno = EPERM;
100 # endif
101         return -1;
102     }
103     locked = 0;
104     LeaveCriticalSection(&_sodium_lock);
105 
106     return 0;
107 }
108 
109 #elif defined(HAVE_PTHREAD) && !defined(__EMSCRIPTEN__)
110 
111 static pthread_mutex_t _sodium_lock = PTHREAD_MUTEX_INITIALIZER;
112 
113 int
sodium_crit_enter(void)114 sodium_crit_enter(void)
115 {
116     int ret;
117 
118     if ((ret = pthread_mutex_lock(&_sodium_lock)) == 0) {
119         assert(locked == 0);
120         locked = 1;
121     }
122     return ret;
123 }
124 
125 int
sodium_crit_leave(void)126 sodium_crit_leave(void)
127 {
128     if (locked == 0) {
129 # ifdef EPERM
130         errno = EPERM;
131 # endif
132         return -1;
133     }
134     locked = 0;
135 
136     return pthread_mutex_unlock(&_sodium_lock);
137 }
138 
139 #elif defined(HAVE_ATOMIC_OPS) && !defined(__EMSCRIPTEN__)
140 
141 static volatile int _sodium_lock;
142 
143 int
sodium_crit_enter(void)144 sodium_crit_enter(void)
145 {
146 # ifdef HAVE_NANOSLEEP
147     struct timespec q;
148     memset(&q, 0, sizeof q);
149 # endif
150     while (__sync_lock_test_and_set(&_sodium_lock, 1) != 0) {
151 # ifdef HAVE_NANOSLEEP
152         (void) nanosleep(&q, NULL);
153 # elif defined(__x86_64__) || defined(__i386__)
154         __asm__ __volatile__ ("pause");
155 # endif
156     }
157     return 0;
158 }
159 
160 int
sodium_crit_leave(void)161 sodium_crit_leave(void)
162 {
163     __sync_lock_release(&_sodium_lock);
164 
165     return 0;
166 }
167 
168 #else
169 
170 int
sodium_crit_enter(void)171 sodium_crit_enter(void)
172 {
173     return 0;
174 }
175 
176 int
sodium_crit_leave(void)177 sodium_crit_leave(void)
178 {
179     return 0;
180 }
181 
182 #endif
183 
184 static void (*_misuse_handler)(void);
185 
186 void
sodium_misuse(void)187 sodium_misuse(void)
188 {
189     void (*handler)(void);
190 
191     (void) sodium_crit_leave();
192     if (sodium_crit_enter() == 0) {
193         handler = _misuse_handler;
194         if (handler != NULL) {
195             handler();
196         }
197     }
198 /* LCOV_EXCL_START */
199     abort();
200 }
201 /* LCOV_EXCL_STOP */
202 
203 int
sodium_set_misuse_handler(void (* handler)(void))204 sodium_set_misuse_handler(void (*handler)(void))
205 {
206     if (sodium_crit_enter() != 0) {
207         return -1; /* LCOV_EXCL_LINE */
208     }
209     _misuse_handler = handler;
210     if (sodium_crit_leave() != 0) {
211         return -1; /* LCOV_EXCL_LINE */
212     }
213     return 0;
214 }
215