1 /* 2 * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <openssl/crypto.h> 11 #include <openssl/core_dispatch.h> 12 #include "crypto/cryptlib.h" 13 #include "prov/providercommon.h" 14 #include "internal/thread_once.h" 15 #include "crypto/context.h" 16 17 #ifdef FIPS_MODULE 18 #include "prov/provider_ctx.h" 19 20 /* 21 * Thread aware code may want to be told about thread stop events. We register 22 * to hear about those thread stop events when we see a new thread has started. 23 * We call the ossl_init_thread_start function to do that. In the FIPS provider 24 * we have our own copy of ossl_init_thread_start, which cascades notifications 25 * about threads stopping from libcrypto to all the code in the FIPS provider 26 * that needs to know about it. 27 * 28 * The FIPS provider tells libcrypto about which threads it is interested in 29 * by calling "c_thread_start" which is a function pointer created during 30 * provider initialisation (i.e. OSSL_provider_init). 31 */ 32 extern OSSL_FUNC_core_thread_start_fn *c_thread_start; 33 #endif 34 35 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER; 36 struct thread_event_handler_st { 37 #ifndef FIPS_MODULE 38 const void *index; 39 #endif 40 void *arg; 41 OSSL_thread_stop_handler_fn handfn; 42 THREAD_EVENT_HANDLER *next; 43 }; 44 45 #ifndef FIPS_MODULE 46 DEFINE_SPECIAL_STACK_OF(THREAD_EVENT_HANDLER_PTR, THREAD_EVENT_HANDLER *) 47 48 typedef struct global_tevent_register_st GLOBAL_TEVENT_REGISTER; 49 struct global_tevent_register_st { 50 STACK_OF(THREAD_EVENT_HANDLER_PTR) *skhands; 51 CRYPTO_RWLOCK *lock; 52 }; 53 54 static GLOBAL_TEVENT_REGISTER *glob_tevent_reg = NULL; 55 56 static CRYPTO_ONCE tevent_register_runonce = CRYPTO_ONCE_STATIC_INIT; 57 58 DEFINE_RUN_ONCE_STATIC(create_global_tevent_register) 59 { 60 glob_tevent_reg = OPENSSL_zalloc(sizeof(*glob_tevent_reg)); 61 if (glob_tevent_reg == NULL) 62 return 0; 63 64 glob_tevent_reg->skhands = sk_THREAD_EVENT_HANDLER_PTR_new_null(); 65 glob_tevent_reg->lock = CRYPTO_THREAD_lock_new(); 66 if (glob_tevent_reg->skhands == NULL || glob_tevent_reg->lock == NULL) { 67 sk_THREAD_EVENT_HANDLER_PTR_free(glob_tevent_reg->skhands); 68 CRYPTO_THREAD_lock_free(glob_tevent_reg->lock); 69 OPENSSL_free(glob_tevent_reg); 70 glob_tevent_reg = NULL; 71 return 0; 72 } 73 74 return 1; 75 } 76 77 static GLOBAL_TEVENT_REGISTER *get_global_tevent_register(void) 78 { 79 if (!RUN_ONCE(&tevent_register_runonce, create_global_tevent_register)) 80 return NULL; 81 return glob_tevent_reg; 82 } 83 #endif 84 85 #ifndef FIPS_MODULE 86 static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands); 87 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin); 88 static void init_thread_destructor(void *hands); 89 static int init_thread_deregister(void *arg, int all); 90 #endif 91 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands); 92 93 static THREAD_EVENT_HANDLER ** 94 init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep) 95 { 96 THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local); 97 98 if (alloc) { 99 if (hands == NULL) { 100 101 if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL) 102 return NULL; 103 104 if (!CRYPTO_THREAD_set_local(local, hands)) { 105 OPENSSL_free(hands); 106 return NULL; 107 } 108 109 #ifndef FIPS_MODULE 110 if (!init_thread_push_handlers(hands)) { 111 CRYPTO_THREAD_set_local(local, NULL); 112 OPENSSL_free(hands); 113 return NULL; 114 } 115 #endif 116 } 117 } else if (!keep) { 118 CRYPTO_THREAD_set_local(local, NULL); 119 } 120 121 return hands; 122 } 123 124 int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *)) 125 { 126 127 #ifndef FIPS_MODULE 128 if (!ossl_init_thread()) 129 return 0; 130 #endif 131 return ossl_thread_init_local(key, cleanup); 132 } 133 134 #ifndef FIPS_MODULE 135 /* 136 * Since per-thread-specific-data destructors are not universally 137 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key 138 * is assumed to have destructor associated. And then an effort is made 139 * to call this single destructor on non-pthread platform[s]. 140 * 141 * Initial value is "impossible". It is used as guard value to shortcut 142 * destructor for threads terminating before libcrypto is initialized or 143 * after it's de-initialized. Access to the key doesn't have to be 144 * serialized for the said threads, because they didn't use libcrypto 145 * and it doesn't matter if they pick "impossible" or dereference real 146 * key value and pull NULL past initialization in the first thread that 147 * intends to use libcrypto. 148 */ 149 static union { 150 long sane; 151 CRYPTO_THREAD_LOCAL value; 152 } destructor_key = { -1 }; 153 154 /* 155 * The thread event handler list is a thread specific linked list 156 * of callback functions which are invoked in list order by the 157 * current thread in case of certain events. (Currently, there is 158 * only one type of event, the 'thread stop' event.) 159 * 160 * We also keep a global reference to that linked list, so that we 161 * can deregister handlers if necessary before all the threads are 162 * stopped. 163 */ 164 static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands) 165 { 166 int ret; 167 GLOBAL_TEVENT_REGISTER *gtr; 168 169 gtr = get_global_tevent_register(); 170 if (gtr == NULL) 171 return 0; 172 173 if (!CRYPTO_THREAD_write_lock(gtr->lock)) 174 return 0; 175 ret = (sk_THREAD_EVENT_HANDLER_PTR_push(gtr->skhands, hands) != 0); 176 CRYPTO_THREAD_unlock(gtr->lock); 177 178 return ret; 179 } 180 181 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin) 182 { 183 GLOBAL_TEVENT_REGISTER *gtr; 184 int i; 185 186 gtr = get_global_tevent_register(); 187 if (gtr == NULL) 188 return; 189 if (!CRYPTO_THREAD_write_lock(gtr->lock)) 190 return; 191 for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) { 192 THREAD_EVENT_HANDLER **hands 193 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i); 194 195 if (hands == handsin) { 196 sk_THREAD_EVENT_HANDLER_PTR_delete(gtr->skhands, i); 197 CRYPTO_THREAD_unlock(gtr->lock); 198 return; 199 } 200 } 201 CRYPTO_THREAD_unlock(gtr->lock); 202 return; 203 } 204 205 static void init_thread_destructor(void *hands) 206 { 207 init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands); 208 init_thread_remove_handlers(hands); 209 OPENSSL_free(hands); 210 } 211 212 static CRYPTO_ONCE ossl_init_thread_runonce = CRYPTO_ONCE_STATIC_INIT; 213 214 DEFINE_RUN_ONCE_STATIC(ossl_init_thread_once) 215 { 216 if (!ossl_thread_init_local(&destructor_key.value, 217 init_thread_destructor)) 218 return 0; 219 220 return 1; 221 } 222 223 int ossl_init_thread(void) 224 { 225 if (!RUN_ONCE(&ossl_init_thread_runonce, ossl_init_thread_once)) 226 return 0; 227 return 1; 228 } 229 230 void ossl_cleanup_thread(void) 231 { 232 init_thread_deregister(NULL, 1); 233 CRYPTO_THREAD_cleanup_local(&destructor_key.value); 234 destructor_key.sane = -1; 235 } 236 237 void OPENSSL_thread_stop_ex(OSSL_LIB_CTX *ctx) 238 { 239 ctx = ossl_lib_ctx_get_concrete(ctx); 240 /* 241 * It would be nice if we could figure out a way to do this on all threads 242 * that have used the OSSL_LIB_CTX when the context is freed. This is 243 * currently not possible due to the use of thread local variables. 244 */ 245 ossl_ctx_thread_stop(ctx); 246 } 247 248 void OPENSSL_thread_stop(void) 249 { 250 if (destructor_key.sane != -1) { 251 THREAD_EVENT_HANDLER **hands 252 = init_get_thread_local(&destructor_key.value, 0, 0); 253 init_thread_stop(NULL, hands); 254 255 init_thread_remove_handlers(hands); 256 OPENSSL_free(hands); 257 } 258 } 259 260 void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx) 261 { 262 if (destructor_key.sane != -1) { 263 THREAD_EVENT_HANDLER **hands 264 = init_get_thread_local(&destructor_key.value, 0, 1); 265 init_thread_stop(ctx, hands); 266 } 267 } 268 269 #else 270 271 static void ossl_arg_thread_stop(void *arg); 272 273 /* Register the current thread so that we are informed if it gets stopped */ 274 int ossl_thread_register_fips(OSSL_LIB_CTX *libctx) 275 { 276 return c_thread_start(FIPS_get_core_handle(libctx), ossl_arg_thread_stop, 277 libctx); 278 } 279 280 void *ossl_thread_event_ctx_new(OSSL_LIB_CTX *libctx) 281 { 282 THREAD_EVENT_HANDLER **hands = NULL; 283 CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal)); 284 285 if (tlocal == NULL) 286 return NULL; 287 288 if (!CRYPTO_THREAD_init_local(tlocal, NULL)) 289 goto deinit; 290 291 hands = OPENSSL_zalloc(sizeof(*hands)); 292 if (hands == NULL) 293 goto err; 294 295 if (!CRYPTO_THREAD_set_local(tlocal, hands)) 296 goto err; 297 298 /* 299 * We should ideally call ossl_thread_register_fips() here. This function 300 * is called during the startup of the FIPS provider and we need to ensure 301 * that the main thread is registered to receive thread callbacks in order 302 * to free |hands| that we allocated above. However we are too early in 303 * the FIPS provider initialisation that FIPS_get_core_handle() doesn't work 304 * yet. So we defer this to the main provider OSSL_provider_init_int() 305 * function. 306 */ 307 308 return tlocal; 309 err: 310 OPENSSL_free(hands); 311 CRYPTO_THREAD_cleanup_local(tlocal); 312 deinit: 313 OPENSSL_free(tlocal); 314 return NULL; 315 } 316 317 void ossl_thread_event_ctx_free(void *tlocal) 318 { 319 CRYPTO_THREAD_cleanup_local(tlocal); 320 OPENSSL_free(tlocal); 321 } 322 323 static void ossl_arg_thread_stop(void *arg) 324 { 325 ossl_ctx_thread_stop((OSSL_LIB_CTX *)arg); 326 } 327 328 void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx) 329 { 330 THREAD_EVENT_HANDLER **hands; 331 CRYPTO_THREAD_LOCAL *local 332 = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX); 333 334 if (local == NULL) 335 return; 336 hands = init_get_thread_local(local, 0, 0); 337 init_thread_stop(ctx, hands); 338 OPENSSL_free(hands); 339 } 340 #endif /* FIPS_MODULE */ 341 342 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands) 343 { 344 THREAD_EVENT_HANDLER *curr, *prev = NULL, *tmp; 345 #ifndef FIPS_MODULE 346 GLOBAL_TEVENT_REGISTER *gtr; 347 #endif 348 349 /* Can't do much about this */ 350 if (hands == NULL) 351 return; 352 353 #ifndef FIPS_MODULE 354 gtr = get_global_tevent_register(); 355 if (gtr == NULL) 356 return; 357 358 if (!CRYPTO_THREAD_write_lock(gtr->lock)) 359 return; 360 #endif 361 362 curr = *hands; 363 while (curr != NULL) { 364 if (arg != NULL && curr->arg != arg) { 365 prev = curr; 366 curr = curr->next; 367 continue; 368 } 369 curr->handfn(curr->arg); 370 if (prev == NULL) 371 *hands = curr->next; 372 else 373 prev->next = curr->next; 374 375 tmp = curr; 376 curr = curr->next; 377 378 OPENSSL_free(tmp); 379 } 380 #ifndef FIPS_MODULE 381 CRYPTO_THREAD_unlock(gtr->lock); 382 #endif 383 } 384 385 int ossl_init_thread_start(const void *index, void *arg, 386 OSSL_thread_stop_handler_fn handfn) 387 { 388 THREAD_EVENT_HANDLER **hands; 389 THREAD_EVENT_HANDLER *hand; 390 #ifdef FIPS_MODULE 391 OSSL_LIB_CTX *ctx = arg; 392 393 /* 394 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination 395 * of OSSL_LIB_CTX and thread. This is because in FIPS mode each 396 * OSSL_LIB_CTX gets informed about thread stop events individually. 397 */ 398 CRYPTO_THREAD_LOCAL *local 399 = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX); 400 #else 401 /* 402 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per 403 * thread, but may hold multiple OSSL_LIB_CTXs. We only get told about 404 * thread stop events globally, so we have to ensure all affected 405 * OSSL_LIB_CTXs are informed. 406 */ 407 CRYPTO_THREAD_LOCAL *local = &destructor_key.value; 408 #endif 409 410 hands = init_get_thread_local(local, 1, 0); 411 if (hands == NULL) 412 return 0; 413 414 #ifdef FIPS_MODULE 415 if (*hands == NULL) { 416 /* 417 * We've not yet registered any handlers for this thread. We need to get 418 * libcrypto to tell us about later thread stop events. c_thread_start 419 * is a callback to libcrypto defined in fipsprov.c 420 */ 421 if (!ossl_thread_register_fips(ctx)) 422 return 0; 423 } 424 #endif 425 426 hand = OPENSSL_malloc(sizeof(*hand)); 427 if (hand == NULL) 428 return 0; 429 430 hand->handfn = handfn; 431 hand->arg = arg; 432 #ifndef FIPS_MODULE 433 hand->index = index; 434 #endif 435 hand->next = *hands; 436 *hands = hand; 437 438 return 1; 439 } 440 441 #ifndef FIPS_MODULE 442 static int init_thread_deregister(void *index, int all) 443 { 444 GLOBAL_TEVENT_REGISTER *gtr; 445 int i; 446 447 gtr = get_global_tevent_register(); 448 if (gtr == NULL) 449 return 0; 450 if (!all) { 451 if (!CRYPTO_THREAD_write_lock(gtr->lock)) 452 return 0; 453 } else { 454 glob_tevent_reg = NULL; 455 } 456 for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) { 457 THREAD_EVENT_HANDLER **hands 458 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i); 459 THREAD_EVENT_HANDLER *curr = NULL, *prev = NULL, *tmp; 460 461 if (hands == NULL) { 462 if (!all) 463 CRYPTO_THREAD_unlock(gtr->lock); 464 return 0; 465 } 466 curr = *hands; 467 while (curr != NULL) { 468 if (all || curr->index == index) { 469 if (prev != NULL) 470 prev->next = curr->next; 471 else 472 *hands = curr->next; 473 tmp = curr; 474 curr = curr->next; 475 OPENSSL_free(tmp); 476 continue; 477 } 478 prev = curr; 479 curr = curr->next; 480 } 481 if (all) 482 OPENSSL_free(hands); 483 } 484 if (all) { 485 CRYPTO_THREAD_lock_free(gtr->lock); 486 sk_THREAD_EVENT_HANDLER_PTR_free(gtr->skhands); 487 OPENSSL_free(gtr); 488 } else { 489 CRYPTO_THREAD_unlock(gtr->lock); 490 } 491 return 1; 492 } 493 494 int ossl_init_thread_deregister(void *index) 495 { 496 return init_thread_deregister(index, 0); 497 } 498 #endif 499