2 * Copyright 2019-2022 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"
15 #include "crypto/context.h"
18 #include "prov/provider_ctx.h"
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.
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_init_provider).
32 extern OSSL_FUNC_core_thread_start_fn
*c_thread_start
;
35 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER
;
36 struct thread_event_handler_st
{
41 OSSL_thread_stop_handler_fn handfn
;
42 THREAD_EVENT_HANDLER
*next
;
46 DEFINE_SPECIAL_STACK_OF(THREAD_EVENT_HANDLER_PTR
, THREAD_EVENT_HANDLER
*)
48 typedef struct global_tevent_register_st GLOBAL_TEVENT_REGISTER
;
49 struct global_tevent_register_st
{
50 STACK_OF(THREAD_EVENT_HANDLER_PTR
) *skhands
;
54 static GLOBAL_TEVENT_REGISTER
*glob_tevent_reg
= NULL
;
56 static CRYPTO_ONCE tevent_register_runonce
= CRYPTO_ONCE_STATIC_INIT
;
58 DEFINE_RUN_ONCE_STATIC(create_global_tevent_register
)
60 glob_tevent_reg
= OPENSSL_zalloc(sizeof(*glob_tevent_reg
));
61 if (glob_tevent_reg
== NULL
)
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
;
77 static GLOBAL_TEVENT_REGISTER
*get_global_tevent_register(void)
79 if (!RUN_ONCE(&tevent_register_runonce
, create_global_tevent_register
))
81 return glob_tevent_reg
;
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
);
91 static void init_thread_stop(void *arg
, THREAD_EVENT_HANDLER
**hands
);
93 static THREAD_EVENT_HANDLER
**
94 init_get_thread_local(CRYPTO_THREAD_LOCAL
*local
, int alloc
, int keep
)
96 THREAD_EVENT_HANDLER
**hands
= CRYPTO_THREAD_get_local(local
);
101 if ((hands
= OPENSSL_zalloc(sizeof(*hands
))) == NULL
)
104 if (!CRYPTO_THREAD_set_local(local
, hands
)) {
110 if (!init_thread_push_handlers(hands
)) {
111 CRYPTO_THREAD_set_local(local
, NULL
);
118 CRYPTO_THREAD_set_local(local
, NULL
);
126 * Since per-thread-specific-data destructors are not universally
127 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
128 * is assumed to have destructor associated. And then an effort is made
129 * to call this single destructor on non-pthread platform[s].
131 * Initial value is "impossible". It is used as guard value to shortcut
132 * destructor for threads terminating before libcrypto is initialized or
133 * after it's de-initialized. Access to the key doesn't have to be
134 * serialized for the said threads, because they didn't use libcrypto
135 * and it doesn't matter if they pick "impossible" or dereference real
136 * key value and pull NULL past initialization in the first thread that
137 * intends to use libcrypto.
141 CRYPTO_THREAD_LOCAL value
;
142 } destructor_key
= { -1 };
145 * The thread event handler list is a thread specific linked list
146 * of callback functions which are invoked in list order by the
147 * current thread in case of certain events. (Currently, there is
148 * only one type of event, the 'thread stop' event.)
150 * We also keep a global reference to that linked list, so that we
151 * can deregister handlers if necessary before all the threads are
154 static int init_thread_push_handlers(THREAD_EVENT_HANDLER
**hands
)
157 GLOBAL_TEVENT_REGISTER
*gtr
;
159 gtr
= get_global_tevent_register();
163 if (!CRYPTO_THREAD_write_lock(gtr
->lock
))
165 ret
= (sk_THREAD_EVENT_HANDLER_PTR_push(gtr
->skhands
, hands
) != 0);
166 CRYPTO_THREAD_unlock(gtr
->lock
);
171 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER
**handsin
)
173 GLOBAL_TEVENT_REGISTER
*gtr
;
176 gtr
= get_global_tevent_register();
179 if (!CRYPTO_THREAD_write_lock(gtr
->lock
))
181 for (i
= 0; i
< sk_THREAD_EVENT_HANDLER_PTR_num(gtr
->skhands
); i
++) {
182 THREAD_EVENT_HANDLER
**hands
183 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr
->skhands
, i
);
185 if (hands
== handsin
) {
186 sk_THREAD_EVENT_HANDLER_PTR_delete(gtr
->skhands
, i
);
187 CRYPTO_THREAD_unlock(gtr
->lock
);
191 CRYPTO_THREAD_unlock(gtr
->lock
);
195 static void init_thread_destructor(void *hands
)
197 init_thread_stop(NULL
, (THREAD_EVENT_HANDLER
**)hands
);
198 init_thread_remove_handlers(hands
);
202 int ossl_init_thread(void)
204 if (!CRYPTO_THREAD_init_local(&destructor_key
.value
,
205 init_thread_destructor
))
211 void ossl_cleanup_thread(void)
213 init_thread_deregister(NULL
, 1);
214 CRYPTO_THREAD_cleanup_local(&destructor_key
.value
);
215 destructor_key
.sane
= -1;
218 void OPENSSL_thread_stop_ex(OSSL_LIB_CTX
*ctx
)
220 ctx
= ossl_lib_ctx_get_concrete(ctx
);
222 * It would be nice if we could figure out a way to do this on all threads
223 * that have used the OSSL_LIB_CTX when the context is freed. This is
224 * currently not possible due to the use of thread local variables.
226 ossl_ctx_thread_stop(ctx
);
229 void OPENSSL_thread_stop(void)
231 if (destructor_key
.sane
!= -1) {
232 THREAD_EVENT_HANDLER
**hands
233 = init_get_thread_local(&destructor_key
.value
, 0, 0);
234 init_thread_stop(NULL
, hands
);
236 init_thread_remove_handlers(hands
);
241 void ossl_ctx_thread_stop(OSSL_LIB_CTX
*ctx
)
243 if (destructor_key
.sane
!= -1) {
244 THREAD_EVENT_HANDLER
**hands
245 = init_get_thread_local(&destructor_key
.value
, 0, 1);
246 init_thread_stop(ctx
, hands
);
252 void *ossl_thread_event_ctx_new(OSSL_LIB_CTX
*libctx
)
254 THREAD_EVENT_HANDLER
**hands
= NULL
;
255 CRYPTO_THREAD_LOCAL
*tlocal
= OPENSSL_zalloc(sizeof(*tlocal
));
260 if (!CRYPTO_THREAD_init_local(tlocal
, NULL
)) {
264 hands
= OPENSSL_zalloc(sizeof(*hands
));
268 if (!CRYPTO_THREAD_set_local(tlocal
, hands
))
274 OPENSSL_free(tlocal
);
278 void ossl_thread_event_ctx_free(void *tlocal
)
280 OPENSSL_free(tlocal
);
283 static void ossl_arg_thread_stop(void *arg
)
285 ossl_ctx_thread_stop((OSSL_LIB_CTX
*)arg
);
288 void ossl_ctx_thread_stop(OSSL_LIB_CTX
*ctx
)
290 THREAD_EVENT_HANDLER
**hands
;
291 CRYPTO_THREAD_LOCAL
*local
292 = ossl_lib_ctx_get_data(ctx
, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX
);
296 hands
= init_get_thread_local(local
, 0, 0);
297 init_thread_stop(ctx
, hands
);
300 #endif /* FIPS_MODULE */
303 static void init_thread_stop(void *arg
, THREAD_EVENT_HANDLER
**hands
)
305 THREAD_EVENT_HANDLER
*curr
, *prev
= NULL
, *tmp
;
307 GLOBAL_TEVENT_REGISTER
*gtr
;
310 /* Can't do much about this */
315 gtr
= get_global_tevent_register();
319 if (!CRYPTO_THREAD_write_lock(gtr
->lock
))
324 while (curr
!= NULL
) {
325 if (arg
!= NULL
&& curr
->arg
!= arg
) {
330 curr
->handfn(curr
->arg
);
334 prev
->next
= curr
->next
;
342 CRYPTO_THREAD_unlock(gtr
->lock
);
346 int ossl_init_thread_start(const void *index
, void *arg
,
347 OSSL_thread_stop_handler_fn handfn
)
349 THREAD_EVENT_HANDLER
**hands
;
350 THREAD_EVENT_HANDLER
*hand
;
352 OSSL_LIB_CTX
*ctx
= arg
;
355 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
356 * of OSSL_LIB_CTX and thread. This is because in FIPS mode each
357 * OSSL_LIB_CTX gets informed about thread stop events individually.
359 CRYPTO_THREAD_LOCAL
*local
360 = ossl_lib_ctx_get_data(ctx
, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX
);
363 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
364 * thread, but may hold multiple OSSL_LIB_CTXs. We only get told about
365 * thread stop events globally, so we have to ensure all affected
366 * OSSL_LIB_CTXs are informed.
368 CRYPTO_THREAD_LOCAL
*local
= &destructor_key
.value
;
371 hands
= init_get_thread_local(local
, 1, 0);
376 if (*hands
== NULL
) {
378 * We've not yet registered any handlers for this thread. We need to get
379 * libcrypto to tell us about later thread stop events. c_thread_start
380 * is a callback to libcrypto defined in fipsprov.c
382 if (!c_thread_start(FIPS_get_core_handle(ctx
), ossl_arg_thread_stop
,
388 hand
= OPENSSL_malloc(sizeof(*hand
));
392 hand
->handfn
= handfn
;
404 static int init_thread_deregister(void *index
, int all
)
406 GLOBAL_TEVENT_REGISTER
*gtr
;
409 gtr
= get_global_tevent_register();
413 if (!CRYPTO_THREAD_write_lock(gtr
->lock
))
416 glob_tevent_reg
= NULL
;
418 for (i
= 0; i
< sk_THREAD_EVENT_HANDLER_PTR_num(gtr
->skhands
); i
++) {
419 THREAD_EVENT_HANDLER
**hands
420 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr
->skhands
, i
);
421 THREAD_EVENT_HANDLER
*curr
= NULL
, *prev
= NULL
, *tmp
;
425 CRYPTO_THREAD_unlock(gtr
->lock
);
429 while (curr
!= NULL
) {
430 if (all
|| curr
->index
== index
) {
432 prev
->next
= curr
->next
;
447 CRYPTO_THREAD_lock_free(gtr
->lock
);
448 sk_THREAD_EVENT_HANDLER_PTR_free(gtr
->skhands
);
451 CRYPTO_THREAD_unlock(gtr
->lock
);
456 int ossl_init_thread_deregister(void *index
)
458 return init_thread_deregister(index
, 0);