1 /* Copyright (c) 2015, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15 #include "internal.h" 16 17 #if defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) 18 19 #pragma warning(push, 3) 20 #include <windows.h> 21 #pragma warning(pop) 22 23 #include <assert.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include <openssl/mem.h> 28 #include <openssl/type_check.h> 29 30 31 OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(CRITICAL_SECTION), 32 CRYPTO_MUTEX_too_small); 33 34 static void run_once(CRYPTO_once_t *in_once, void (*init)(void *), void *arg) { 35 volatile LONG *once = in_once; 36 37 /* Values must be aligned. */ 38 assert((((uintptr_t) once) & 3) == 0); 39 40 /* This assumes that reading *once has acquire semantics. This should be true 41 * on x86 and x86-64, where we expect Windows to run. */ 42 #if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) 43 #error "Windows once code may not work on other platforms." \ 44 "You can use InitOnceBeginInitialize on >=Vista" 45 #endif 46 if (*once == 1) { 47 return; 48 } 49 50 for (;;) { 51 switch (InterlockedCompareExchange(once, 2, 0)) { 52 case 0: 53 /* The value was zero so we are the first thread to call |CRYPTO_once| 54 * on it. */ 55 init(arg); 56 /* Write one to indicate that initialisation is complete. */ 57 InterlockedExchange(once, 1); 58 return; 59 60 case 1: 61 /* Another thread completed initialisation between our fast-path check 62 * and |InterlockedCompareExchange|. */ 63 return; 64 65 case 2: 66 /* Another thread is running the initialisation. Switch to it then try 67 * again. */ 68 SwitchToThread(); 69 break; 70 71 default: 72 abort(); 73 } 74 } 75 } 76 77 static void call_once_init(void *arg) { 78 void (*init_func)(void); 79 /* MSVC does not like casting between data and function pointers. */ 80 memcpy(&init_func, &arg, sizeof(void *)); 81 init_func(); 82 } 83 84 void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) { 85 void *arg; 86 /* MSVC does not like casting between data and function pointers. */ 87 memcpy(&arg, &init, sizeof(void *)); 88 run_once(in_once, call_once_init, arg); 89 } 90 91 void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { 92 if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, 0x400)) { 93 abort(); 94 } 95 } 96 97 void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { 98 /* Since we have to support Windows XP, read locks are actually exclusive. */ 99 EnterCriticalSection((CRITICAL_SECTION *) lock); 100 } 101 102 void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { 103 EnterCriticalSection((CRITICAL_SECTION *) lock); 104 } 105 106 void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { 107 LeaveCriticalSection((CRITICAL_SECTION *) lock); 108 } 109 110 void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { 111 DeleteCriticalSection((CRITICAL_SECTION *) lock); 112 } 113 114 static void static_lock_init(void *arg) { 115 struct CRYPTO_STATIC_MUTEX *lock = arg; 116 if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) { 117 abort(); 118 } 119 } 120 121 void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { 122 /* Since we have to support Windows XP, read locks are actually exclusive. */ 123 run_once(&lock->once, static_lock_init, lock); 124 EnterCriticalSection(&lock->lock); 125 } 126 127 void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { 128 CRYPTO_STATIC_MUTEX_lock_read(lock); 129 } 130 131 void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { 132 LeaveCriticalSection(&lock->lock); 133 } 134 135 static CRITICAL_SECTION g_destructors_lock; 136 static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS]; 137 138 static CRYPTO_once_t g_thread_local_init_once = CRYPTO_ONCE_INIT; 139 static DWORD g_thread_local_key; 140 static int g_thread_local_failed; 141 142 static void thread_local_init(void) { 143 if (!InitializeCriticalSectionAndSpinCount(&g_destructors_lock, 0x400)) { 144 g_thread_local_failed = 1; 145 return; 146 } 147 g_thread_local_key = TlsAlloc(); 148 g_thread_local_failed = (g_thread_local_key == TLS_OUT_OF_INDEXES); 149 } 150 151 static void NTAPI thread_local_destructor(PVOID module, 152 DWORD reason, PVOID reserved) { 153 if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) { 154 return; 155 } 156 157 CRYPTO_once(&g_thread_local_init_once, thread_local_init); 158 if (g_thread_local_failed) { 159 return; 160 } 161 162 void **pointers = (void**) TlsGetValue(g_thread_local_key); 163 if (pointers == NULL) { 164 return; 165 } 166 167 thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; 168 169 EnterCriticalSection(&g_destructors_lock); 170 memcpy(destructors, g_destructors, sizeof(destructors)); 171 LeaveCriticalSection(&g_destructors_lock); 172 173 unsigned i; 174 for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) { 175 if (destructors[i] != NULL) { 176 destructors[i](pointers[i]); 177 } 178 } 179 180 OPENSSL_free(pointers); 181 } 182 183 /* Thread Termination Callbacks. 184 * 185 * Windows doesn't support a per-thread destructor with its TLS primitives. 186 * So, we build it manually by inserting a function to be called on each 187 * thread's exit. This magic is from http://www.codeproject.com/threads/tls.asp 188 * and it works for VC++ 7.0 and later. 189 * 190 * Force a reference to _tls_used to make the linker create the TLS directory 191 * if it's not already there. (E.g. if __declspec(thread) is not used). Force 192 * a reference to p_thread_callback_boringssl to prevent whole program 193 * optimization from discarding the variable. */ 194 #ifdef _WIN64 195 #pragma comment(linker, "/INCLUDE:_tls_used") 196 #pragma comment(linker, "/INCLUDE:p_thread_callback_boringssl") 197 #else 198 #pragma comment(linker, "/INCLUDE:__tls_used") 199 #pragma comment(linker, "/INCLUDE:_p_thread_callback_boringssl") 200 #endif 201 202 /* .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are 203 * called automatically by the OS loader code (not the CRT) when the module is 204 * loaded and on thread creation. They are NOT called if the module has been 205 * loaded by a LoadLibrary() call. It must have implicitly been loaded at 206 * process startup. 207 * 208 * By implicitly loaded, I mean that it is directly referenced by the main EXE 209 * or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being 210 * implicitly loaded. 211 * 212 * See VC\crt\src\tlssup.c for reference. */ 213 214 /* The linker must not discard p_thread_callback_boringssl. (We force a reference 215 * to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If 216 * this variable is discarded, the OnThreadExit function will never be 217 * called. */ 218 #ifdef _WIN64 219 220 /* .CRT section is merged with .rdata on x64 so it must be constant data. */ 221 #pragma const_seg(".CRT$XLC") 222 /* When defining a const variable, it must have external linkage to be sure the 223 * linker doesn't discard it. */ 224 extern const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl; 225 const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor; 226 /* Reset the default section. */ 227 #pragma const_seg() 228 229 #else 230 231 #pragma data_seg(".CRT$XLC") 232 PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor; 233 /* Reset the default section. */ 234 #pragma data_seg() 235 236 #endif /* _WIN64 */ 237 238 void *CRYPTO_get_thread_local(thread_local_data_t index) { 239 CRYPTO_once(&g_thread_local_init_once, thread_local_init); 240 if (g_thread_local_failed) { 241 return NULL; 242 } 243 244 void **pointers = TlsGetValue(g_thread_local_key); 245 if (pointers == NULL) { 246 return NULL; 247 } 248 return pointers[index]; 249 } 250 251 int CRYPTO_set_thread_local(thread_local_data_t index, void *value, 252 thread_local_destructor_t destructor) { 253 CRYPTO_once(&g_thread_local_init_once, thread_local_init); 254 if (g_thread_local_failed) { 255 destructor(value); 256 return 0; 257 } 258 259 void **pointers = TlsGetValue(g_thread_local_key); 260 if (pointers == NULL) { 261 pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); 262 if (pointers == NULL) { 263 destructor(value); 264 return 0; 265 } 266 memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); 267 if (TlsSetValue(g_thread_local_key, pointers) == 0) { 268 OPENSSL_free(pointers); 269 destructor(value); 270 return 0; 271 } 272 } 273 274 EnterCriticalSection(&g_destructors_lock); 275 g_destructors[index] = destructor; 276 LeaveCriticalSection(&g_destructors_lock); 277 278 pointers[index] = value; 279 return 1; 280 } 281 282 #endif /* OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ 283