2 * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
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
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"
17 #include "prov/provider_ctx.h"
20 * Thread aware code may want to be told about thread stop events. We register
21 * to hear about those thread stop events when we see a new thread has started.
22 * We call the ossl_init_thread_start function to do that. In the FIPS provider
23 * we have our own copy of ossl_init_thread_start, which cascades notifications
24 * about threads stopping from libcrypto to all the code in the FIPS provider
25 * that needs to know about it.
27 * The FIPS provider tells libcrypto about which threads it is interested in
28 * by calling "c_thread_start" which is a function pointer created during
29 * provider initialisation (i.e. OSSL_init_provider).
31 extern OSSL_FUNC_core_thread_start_fn *c_thread_start;
34 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
35 struct thread_event_handler_st {
40 OSSL_thread_stop_handler_fn handfn;
41 THREAD_EVENT_HANDLER *next;
45 DEFINE_SPECIAL_STACK_OF(THREAD_EVENT_HANDLER_PTR, THREAD_EVENT_HANDLER *)
47 typedef struct global_tevent_register_st GLOBAL_TEVENT_REGISTER;
48 struct global_tevent_register_st {
49 STACK_OF(THREAD_EVENT_HANDLER_PTR) *skhands;
53 static GLOBAL_TEVENT_REGISTER *glob_tevent_reg = NULL;
55 static CRYPTO_ONCE tevent_register_runonce = CRYPTO_ONCE_STATIC_INIT;
57 DEFINE_RUN_ONCE_STATIC(create_global_tevent_register)
59 glob_tevent_reg = OPENSSL_zalloc(sizeof(*glob_tevent_reg));
60 if (glob_tevent_reg == NULL)
63 glob_tevent_reg->skhands = sk_THREAD_EVENT_HANDLER_PTR_new_null();
64 glob_tevent_reg->lock = CRYPTO_THREAD_lock_new();
65 if (glob_tevent_reg->skhands == NULL || glob_tevent_reg->lock == NULL) {
66 sk_THREAD_EVENT_HANDLER_PTR_free(glob_tevent_reg->skhands);
67 CRYPTO_THREAD_lock_free(glob_tevent_reg->lock);
68 OPENSSL_free(glob_tevent_reg);
69 glob_tevent_reg = NULL;
76 static GLOBAL_TEVENT_REGISTER *get_global_tevent_register(void)
78 if (!RUN_ONCE(&tevent_register_runonce, create_global_tevent_register))
80 return glob_tevent_reg;
85 static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands);
86 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin);
87 static void init_thread_destructor(void *hands);
88 static int init_thread_deregister(void *arg, int all);
90 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
92 static THREAD_EVENT_HANDLER **
93 init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
95 THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local);
100 if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL)
103 if (!CRYPTO_THREAD_set_local(local, hands)) {
109 if (!init_thread_push_handlers(hands)) {
110 CRYPTO_THREAD_set_local(local, NULL);
117 CRYPTO_THREAD_set_local(local, NULL);
125 * Since per-thread-specific-data destructors are not universally
126 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
127 * is assumed to have destructor associated. And then an effort is made
128 * to call this single destructor on non-pthread platform[s].
130 * Initial value is "impossible". It is used as guard value to shortcut
131 * destructor for threads terminating before libcrypto is initialized or
132 * after it's de-initialized. Access to the key doesn't have to be
133 * serialized for the said threads, because they didn't use libcrypto
134 * and it doesn't matter if they pick "impossible" or dereference real
135 * key value and pull NULL past initialization in the first thread that
136 * intends to use libcrypto.
140 CRYPTO_THREAD_LOCAL value;
141 } destructor_key = { -1 };
144 * The thread event handler list is a thread specific linked list
145 * of callback functions which are invoked in list order by the
146 * current thread in case of certain events. (Currently, there is
147 * only one type of event, the 'thread stop' event.)
149 * We also keep a global reference to that linked list, so that we
150 * can deregister handlers if necessary before all the threads are
153 static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands)
156 GLOBAL_TEVENT_REGISTER *gtr;
158 gtr = get_global_tevent_register();
162 if (!CRYPTO_THREAD_write_lock(gtr->lock))
164 ret = (sk_THREAD_EVENT_HANDLER_PTR_push(gtr->skhands, hands) != 0);
165 CRYPTO_THREAD_unlock(gtr->lock);
170 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin)
172 GLOBAL_TEVENT_REGISTER *gtr;
175 gtr = get_global_tevent_register();
178 if (!CRYPTO_THREAD_write_lock(gtr->lock))
180 for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
181 THREAD_EVENT_HANDLER **hands
182 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
184 if (hands == handsin) {
185 sk_THREAD_EVENT_HANDLER_PTR_delete(gtr->skhands, i);
186 CRYPTO_THREAD_unlock(gtr->lock);
190 CRYPTO_THREAD_unlock(gtr->lock);
194 static void init_thread_destructor(void *hands)
196 init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands);
197 init_thread_remove_handlers(hands);
201 int ossl_init_thread(void)
203 if (!CRYPTO_THREAD_init_local(&destructor_key.value,
204 init_thread_destructor))
210 void ossl_cleanup_thread(void)
212 init_thread_deregister(NULL, 1);
213 CRYPTO_THREAD_cleanup_local(&destructor_key.value);
214 destructor_key.sane = -1;
217 void OPENSSL_thread_stop_ex(OSSL_LIB_CTX *ctx)
219 ctx = ossl_lib_ctx_get_concrete(ctx);
221 * It would be nice if we could figure out a way to do this on all threads
222 * that have used the OSSL_LIB_CTX when the context is freed. This is
223 * currently not possible due to the use of thread local variables.
225 ossl_ctx_thread_stop(ctx);
228 void OPENSSL_thread_stop(void)
230 if (destructor_key.sane != -1) {
231 THREAD_EVENT_HANDLER **hands
232 = init_get_thread_local(&destructor_key.value, 0, 0);
233 init_thread_stop(NULL, hands);
235 init_thread_remove_handlers(hands);
240 void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx)
242 if (destructor_key.sane != -1) {
243 THREAD_EVENT_HANDLER **hands
244 = init_get_thread_local(&destructor_key.value, 0, 1);
245 init_thread_stop(ctx, hands);
251 static void *thread_event_ossl_ctx_new(OSSL_LIB_CTX *libctx)
253 THREAD_EVENT_HANDLER **hands = NULL;
254 CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
259 if (!CRYPTO_THREAD_init_local(tlocal, NULL)) {
263 hands = OPENSSL_zalloc(sizeof(*hands));
267 if (!CRYPTO_THREAD_set_local(tlocal, hands))
273 OPENSSL_free(tlocal);
277 static void thread_event_ossl_ctx_free(void *tlocal)
279 OPENSSL_free(tlocal);
282 static const OSSL_LIB_CTX_METHOD thread_event_ossl_ctx_method = {
283 OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
284 thread_event_ossl_ctx_new,
285 thread_event_ossl_ctx_free,
288 static void ossl_arg_thread_stop(void *arg)
290 ossl_ctx_thread_stop((OSSL_LIB_CTX *)arg);
293 void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx)
295 THREAD_EVENT_HANDLER **hands;
296 CRYPTO_THREAD_LOCAL *local
297 = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX,
298 &thread_event_ossl_ctx_method);
302 hands = init_get_thread_local(local, 0, 0);
303 init_thread_stop(ctx, hands);
306 #endif /* FIPS_MODULE */
309 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands)
311 THREAD_EVENT_HANDLER *curr, *prev = NULL, *tmp;
313 GLOBAL_TEVENT_REGISTER *gtr;
316 /* Can't do much about this */
321 gtr = get_global_tevent_register();
325 if (!CRYPTO_THREAD_write_lock(gtr->lock))
330 while (curr != NULL) {
331 if (arg != NULL && curr->arg != arg) {
336 curr->handfn(curr->arg);
340 prev->next = curr->next;
348 CRYPTO_THREAD_unlock(gtr->lock);
352 int ossl_init_thread_start(const void *index, void *arg,
353 OSSL_thread_stop_handler_fn handfn)
355 THREAD_EVENT_HANDLER **hands;
356 THREAD_EVENT_HANDLER *hand;
358 OSSL_LIB_CTX *ctx = arg;
361 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
362 * of OSSL_LIB_CTX and thread. This is because in FIPS mode each
363 * OSSL_LIB_CTX gets informed about thread stop events individually.
365 CRYPTO_THREAD_LOCAL *local
366 = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX,
367 &thread_event_ossl_ctx_method);
370 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
371 * thread, but may hold multiple OSSL_LIB_CTXs. We only get told about
372 * thread stop events globally, so we have to ensure all affected
373 * OSSL_LIB_CTXs are informed.
375 CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
378 hands = init_get_thread_local(local, 1, 0);
383 if (*hands == NULL) {
385 * We've not yet registered any handlers for this thread. We need to get
386 * libcrypto to tell us about later thread stop events. c_thread_start
387 * is a callback to libcrypto defined in fipsprov.c
389 if (!c_thread_start(FIPS_get_core_handle(ctx), ossl_arg_thread_stop,
395 hand = OPENSSL_malloc(sizeof(*hand));
399 hand->handfn = handfn;
411 static int init_thread_deregister(void *index, int all)
413 GLOBAL_TEVENT_REGISTER *gtr;
416 gtr = get_global_tevent_register();
420 if (!CRYPTO_THREAD_write_lock(gtr->lock))
423 glob_tevent_reg = NULL;
425 for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
426 THREAD_EVENT_HANDLER **hands
427 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
428 THREAD_EVENT_HANDLER *curr = NULL, *prev = NULL, *tmp;
432 CRYPTO_THREAD_unlock(gtr->lock);
436 while (curr != NULL) {
437 if (all || curr->index == index) {
439 prev->next = curr->next;
454 CRYPTO_THREAD_lock_free(gtr->lock);
455 sk_THREAD_EVENT_HANDLER_PTR_free(gtr->skhands);
458 CRYPTO_THREAD_unlock(gtr->lock);
463 int ossl_init_thread_deregister(void *index)
465 return init_thread_deregister(index, 0);