2 * Copyright 2019-2020 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_numbers.h>
12 #include "crypto/cryptlib.h"
13 #include "prov/providercommon.h"
14 #include "internal/thread_once.h"
18 * Thread aware code may want to be told about thread stop events. We register
19 * to hear about those thread stop events when we see a new thread has started.
20 * We call the ossl_init_thread_start function to do that. In the FIPS provider
21 * we have our own copy of ossl_init_thread_start, which cascades notifications
22 * about threads stopping from libcrypto to all the code in the FIPS provider
23 * that needs to know about it.
25 * The FIPS provider tells libcrypto about which threads it is interested in
26 * by calling "c_thread_start" which is a function pointer created during
27 * provider initialisation (i.e. OSSL_init_provider).
29 extern OSSL_core_thread_start_fn
*c_thread_start
;
32 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER
;
33 struct thread_event_handler_st
{
36 OSSL_thread_stop_handler_fn handfn
;
37 THREAD_EVENT_HANDLER
*next
;
41 DEFINE_SPECIAL_STACK_OF(THREAD_EVENT_HANDLER_PTR
, THREAD_EVENT_HANDLER
*)
43 typedef struct global_tevent_register_st GLOBAL_TEVENT_REGISTER
;
44 struct global_tevent_register_st
{
45 STACK_OF(THREAD_EVENT_HANDLER_PTR
) *skhands
;
49 static GLOBAL_TEVENT_REGISTER
*glob_tevent_reg
= NULL
;
51 static CRYPTO_ONCE tevent_register_runonce
= CRYPTO_ONCE_STATIC_INIT
;
53 DEFINE_RUN_ONCE_STATIC(create_global_tevent_register
)
55 glob_tevent_reg
= OPENSSL_zalloc(sizeof(*glob_tevent_reg
));
56 if (glob_tevent_reg
== NULL
)
59 glob_tevent_reg
->skhands
= sk_THREAD_EVENT_HANDLER_PTR_new_null();
60 glob_tevent_reg
->lock
= CRYPTO_THREAD_lock_new();
61 if (glob_tevent_reg
->skhands
== NULL
|| glob_tevent_reg
->lock
== NULL
) {
62 sk_THREAD_EVENT_HANDLER_PTR_free(glob_tevent_reg
->skhands
);
63 CRYPTO_THREAD_lock_free(glob_tevent_reg
->lock
);
64 OPENSSL_free(glob_tevent_reg
);
65 glob_tevent_reg
= NULL
;
72 static GLOBAL_TEVENT_REGISTER
*get_global_tevent_register(void)
74 if (!RUN_ONCE(&tevent_register_runonce
, create_global_tevent_register
))
76 return glob_tevent_reg
;
81 static int init_thread_push_handlers(THREAD_EVENT_HANDLER
**hands
);
82 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER
**handsin
);
83 static void init_thread_destructor(void *hands
);
84 static int init_thread_deregister(void *arg
, int all
);
86 static void init_thread_stop(void *arg
, THREAD_EVENT_HANDLER
**hands
);
88 static THREAD_EVENT_HANDLER
**
89 init_get_thread_local(CRYPTO_THREAD_LOCAL
*local
, int alloc
, int keep
)
91 THREAD_EVENT_HANDLER
**hands
= CRYPTO_THREAD_get_local(local
);
96 if ((hands
= OPENSSL_zalloc(sizeof(*hands
))) == NULL
)
99 if (!CRYPTO_THREAD_set_local(local
, hands
)) {
105 if (!init_thread_push_handlers(hands
)) {
106 CRYPTO_THREAD_set_local(local
, NULL
);
113 CRYPTO_THREAD_set_local(local
, NULL
);
121 * Since per-thread-specific-data destructors are not universally
122 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
123 * is assumed to have destructor associated. And then an effort is made
124 * to call this single destructor on non-pthread platform[s].
126 * Initial value is "impossible". It is used as guard value to shortcut
127 * destructor for threads terminating before libcrypto is initialized or
128 * after it's de-initialized. Access to the key doesn't have to be
129 * serialized for the said threads, because they didn't use libcrypto
130 * and it doesn't matter if they pick "impossible" or dereference real
131 * key value and pull NULL past initialization in the first thread that
132 * intends to use libcrypto.
136 CRYPTO_THREAD_LOCAL value
;
137 } destructor_key
= { -1 };
140 * The thread event handler list is a thread specific linked list
141 * of callback functions which are invoked in list order by the
142 * current thread in case of certain events. (Currently, there is
143 * only one type of event, the 'thread stop' event.)
145 * We also keep a global reference to that linked list, so that we
146 * can deregister handlers if necessary before all the threads are
149 static int init_thread_push_handlers(THREAD_EVENT_HANDLER
**hands
)
152 GLOBAL_TEVENT_REGISTER
*gtr
;
154 gtr
= get_global_tevent_register();
158 CRYPTO_THREAD_write_lock(gtr
->lock
);
159 ret
= (sk_THREAD_EVENT_HANDLER_PTR_push(gtr
->skhands
, hands
) != 0);
160 CRYPTO_THREAD_unlock(gtr
->lock
);
165 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER
**handsin
)
167 GLOBAL_TEVENT_REGISTER
*gtr
;
170 gtr
= get_global_tevent_register();
173 CRYPTO_THREAD_write_lock(gtr
->lock
);
174 for (i
= 0; i
< sk_THREAD_EVENT_HANDLER_PTR_num(gtr
->skhands
); i
++) {
175 THREAD_EVENT_HANDLER
**hands
176 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr
->skhands
, i
);
178 if (hands
== handsin
) {
179 hands
= sk_THREAD_EVENT_HANDLER_PTR_delete(gtr
->skhands
, i
);
180 CRYPTO_THREAD_unlock(gtr
->lock
);
184 CRYPTO_THREAD_unlock(gtr
->lock
);
188 static void init_thread_destructor(void *hands
)
190 init_thread_stop(NULL
, (THREAD_EVENT_HANDLER
**)hands
);
191 init_thread_remove_handlers(hands
);
195 int ossl_init_thread(void)
197 if (!CRYPTO_THREAD_init_local(&destructor_key
.value
,
198 init_thread_destructor
))
204 void ossl_cleanup_thread(void)
206 init_thread_deregister(NULL
, 1);
207 CRYPTO_THREAD_cleanup_local(&destructor_key
.value
);
208 destructor_key
.sane
= -1;
211 void OPENSSL_thread_stop_ex(OPENSSL_CTX
*ctx
)
213 ctx
= openssl_ctx_get_concrete(ctx
);
215 * TODO(3.0). It would be nice if we could figure out a way to do this on
216 * all threads that have used the OPENSSL_CTX when the OPENSSL_CTX is freed.
217 * This is currently not possible due to the use of thread local variables.
219 ossl_ctx_thread_stop(ctx
);
222 void OPENSSL_thread_stop(void)
224 if (destructor_key
.sane
!= -1) {
225 THREAD_EVENT_HANDLER
**hands
226 = init_get_thread_local(&destructor_key
.value
, 0, 0);
227 init_thread_stop(NULL
, hands
);
229 init_thread_remove_handlers(hands
);
234 void ossl_ctx_thread_stop(void *arg
)
236 if (destructor_key
.sane
!= -1) {
237 THREAD_EVENT_HANDLER
**hands
238 = init_get_thread_local(&destructor_key
.value
, 0, 1);
239 init_thread_stop(arg
, hands
);
245 static void *thread_event_ossl_ctx_new(OPENSSL_CTX
*libctx
)
247 THREAD_EVENT_HANDLER
**hands
= NULL
;
248 CRYPTO_THREAD_LOCAL
*tlocal
= OPENSSL_zalloc(sizeof(*tlocal
));
253 if (!CRYPTO_THREAD_init_local(tlocal
, NULL
)) {
257 hands
= OPENSSL_zalloc(sizeof(*hands
));
261 if (!CRYPTO_THREAD_set_local(tlocal
, hands
))
267 OPENSSL_free(tlocal
);
271 static void thread_event_ossl_ctx_free(void *tlocal
)
273 OPENSSL_free(tlocal
);
276 static const OPENSSL_CTX_METHOD thread_event_ossl_ctx_method
= {
277 thread_event_ossl_ctx_new
,
278 thread_event_ossl_ctx_free
,
281 void ossl_ctx_thread_stop(void *arg
)
283 THREAD_EVENT_HANDLER
**hands
;
284 OPENSSL_CTX
*ctx
= arg
;
285 CRYPTO_THREAD_LOCAL
*local
286 = openssl_ctx_get_data(ctx
, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX
,
287 &thread_event_ossl_ctx_method
);
291 hands
= init_get_thread_local(local
, 0, 0);
292 init_thread_stop(arg
, hands
);
295 #endif /* FIPS_MODULE */
298 static void init_thread_stop(void *arg
, THREAD_EVENT_HANDLER
**hands
)
300 THREAD_EVENT_HANDLER
*curr
, *prev
= NULL
, *tmp
;
302 /* Can't do much about this */
307 while (curr
!= NULL
) {
308 if (arg
!= NULL
&& curr
->arg
!= arg
) {
313 curr
->handfn(curr
->arg
);
317 prev
->next
= curr
->next
;
326 int ossl_init_thread_start(const void *index
, void *arg
,
327 OSSL_thread_stop_handler_fn handfn
)
329 THREAD_EVENT_HANDLER
**hands
;
330 THREAD_EVENT_HANDLER
*hand
;
332 OPENSSL_CTX
*ctx
= arg
;
335 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
336 * of OPENSSL_CTX and thread. This is because in FIPS mode each OPENSSL_CTX
337 * gets informed about thread stop events individually.
339 CRYPTO_THREAD_LOCAL
*local
340 = openssl_ctx_get_data(ctx
, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX
,
341 &thread_event_ossl_ctx_method
);
344 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
345 * thread, but may hold multiple OPENSSL_CTXs. We only get told about
346 * thread stop events globally, so we have to ensure all affected
347 * OPENSSL_CTXs are informed.
349 CRYPTO_THREAD_LOCAL
*local
= &destructor_key
.value
;
352 hands
= init_get_thread_local(local
, 1, 0);
357 if (*hands
== NULL
) {
359 * We've not yet registered any handlers for this thread. We need to get
360 * libcrypto to tell us about later thread stop events. c_thread_start
361 * is a callback to libcrypto defined in fipsprov.c
363 if (!c_thread_start(FIPS_get_core_handle(ctx
), ossl_ctx_thread_stop
))
368 hand
= OPENSSL_malloc(sizeof(*hand
));
372 hand
->handfn
= handfn
;
382 static int init_thread_deregister(void *index
, int all
)
384 GLOBAL_TEVENT_REGISTER
*gtr
;
387 gtr
= get_global_tevent_register();
391 CRYPTO_THREAD_write_lock(gtr
->lock
);
392 for (i
= 0; i
< sk_THREAD_EVENT_HANDLER_PTR_num(gtr
->skhands
); i
++) {
393 THREAD_EVENT_HANDLER
**hands
394 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr
->skhands
, i
);
395 THREAD_EVENT_HANDLER
*curr
= *hands
, *prev
= NULL
, *tmp
;
399 CRYPTO_THREAD_unlock(gtr
->lock
);
402 while (curr
!= NULL
) {
403 if (all
|| curr
->index
== index
) {
405 prev
->next
= curr
->next
;
420 CRYPTO_THREAD_lock_free(gtr
->lock
);
421 sk_THREAD_EVENT_HANDLER_PTR_free(gtr
->skhands
);
424 CRYPTO_THREAD_unlock(gtr
->lock
);
429 int ossl_init_thread_deregister(void *index
)
431 return init_thread_deregister(index
, 0);