2 * Copyright 2019 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 "internal/cryptlib_int.h"
13 #include "internal/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;
80 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
82 static THREAD_EVENT_HANDLER **
83 init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
85 THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local);
90 GLOBAL_TEVENT_REGISTER *gtr;
93 if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL) {
100 * The thread event handler is thread specific and is a linked
101 * list of all handler functions that should be called for the
102 * current thread. We also keep a global reference to that linked
103 * list, so that we can deregister handlers if necessary before all
104 * the threads are stopped.
106 gtr = get_global_tevent_register();
111 CRYPTO_THREAD_write_lock(gtr->lock);
112 if (!sk_THREAD_EVENT_HANDLER_PTR_push(gtr->skhands, hands)) {
114 CRYPTO_THREAD_unlock(gtr->lock);
117 CRYPTO_THREAD_unlock(gtr->lock);
119 if (!CRYPTO_THREAD_set_local(local, hands)) {
125 CRYPTO_THREAD_set_local(local, NULL);
133 * Since per-thread-specific-data destructors are not universally
134 * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
135 * is assumed to have destructor associated. And then an effort is made
136 * to call this single destructor on non-pthread platform[s].
138 * Initial value is "impossible". It is used as guard value to shortcut
139 * destructor for threads terminating before libcrypto is initialized or
140 * after it's de-initialized. Access to the key doesn't have to be
141 * serialized for the said threads, because they didn't use libcrypto
142 * and it doesn't matter if they pick "impossible" or dereference real
143 * key value and pull NULL past initialization in the first thread that
144 * intends to use libcrypto.
148 CRYPTO_THREAD_LOCAL value;
149 } destructor_key = { -1 };
151 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin)
153 GLOBAL_TEVENT_REGISTER *gtr;
156 gtr = get_global_tevent_register();
159 CRYPTO_THREAD_write_lock(gtr->lock);
160 for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
161 THREAD_EVENT_HANDLER **hands
162 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
164 if (hands == handsin) {
165 hands = sk_THREAD_EVENT_HANDLER_PTR_delete(gtr->skhands, i);
166 CRYPTO_THREAD_unlock(gtr->lock);
170 CRYPTO_THREAD_unlock(gtr->lock);
174 static void init_thread_destructor(void *hands)
176 init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands);
177 init_thread_remove_handlers(hands);
181 int ossl_init_thread(void)
183 if (!CRYPTO_THREAD_init_local(&destructor_key.value,
184 init_thread_destructor))
190 static int init_thread_deregister(void *arg, int all);
192 void ossl_cleanup_thread(void)
194 init_thread_deregister(NULL, 1);
195 CRYPTO_THREAD_cleanup_local(&destructor_key.value);
196 destructor_key.sane = -1;
199 void OPENSSL_thread_stop_ex(OPENSSL_CTX *ctx)
201 ctx = openssl_ctx_get_concrete(ctx);
203 * TODO(3.0). It would be nice if we could figure out a way to do this on
204 * all threads that have used the OPENSSL_CTX when the OPENSSL_CTX is freed.
205 * This is currently not possible due to the use of thread local variables.
207 ossl_ctx_thread_stop(ctx);
210 void OPENSSL_thread_stop(void)
212 if (destructor_key.sane != -1) {
213 THREAD_EVENT_HANDLER **hands
214 = init_get_thread_local(&destructor_key.value, 0, 0);
215 init_thread_stop(NULL, hands);
217 init_thread_remove_handlers(hands);
222 void ossl_ctx_thread_stop(void *arg)
224 if (destructor_key.sane != -1) {
225 THREAD_EVENT_HANDLER **hands
226 = init_get_thread_local(&destructor_key.value, 0, 1);
227 init_thread_stop(arg, hands);
233 static void *thread_event_ossl_ctx_new(OPENSSL_CTX *libctx)
235 THREAD_EVENT_HANDLER **hands = NULL;
236 CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
241 if (!CRYPTO_THREAD_init_local(tlocal, NULL)) {
245 hands = OPENSSL_zalloc(sizeof(*hands));
249 if (!CRYPTO_THREAD_set_local(tlocal, hands))
255 OPENSSL_free(tlocal);
259 static void thread_event_ossl_ctx_free(void *tlocal)
261 OPENSSL_free(tlocal);
264 static const OPENSSL_CTX_METHOD thread_event_ossl_ctx_method = {
265 thread_event_ossl_ctx_new,
266 thread_event_ossl_ctx_free,
269 void ossl_ctx_thread_stop(void *arg)
271 THREAD_EVENT_HANDLER **hands;
272 OPENSSL_CTX *ctx = arg;
273 CRYPTO_THREAD_LOCAL *local
274 = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
275 &thread_event_ossl_ctx_method);
279 hands = init_get_thread_local(local, 0, 0);
280 init_thread_stop(arg, hands);
283 #endif /* FIPS_MODE */
286 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands)
288 THREAD_EVENT_HANDLER *curr, *prev = NULL;
290 /* Can't do much about this */
295 while (curr != NULL) {
296 if (arg != NULL && curr->arg != arg) {
300 curr->handfn(curr->arg);
309 int ossl_init_thread_start(const void *index, void *arg,
310 OSSL_thread_stop_handler_fn handfn)
312 THREAD_EVENT_HANDLER **hands;
313 THREAD_EVENT_HANDLER *hand;
315 OPENSSL_CTX *ctx = arg;
318 * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
319 * of OPENSSL_CTX and thread. This is because in FIPS mode each OPENSSL_CTX
320 * gets informed about thread stop events individually.
322 CRYPTO_THREAD_LOCAL *local
323 = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
324 &thread_event_ossl_ctx_method);
327 * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
328 * thread, but may hold multiple OPENSSL_CTXs. We only get told about
329 * thread stop events globally, so we have to ensure all affected
330 * OPENSSL_CTXs are informed.
332 CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
335 hands = init_get_thread_local(local, 1, 0);
340 if (*hands == NULL) {
342 * We've not yet registered any handlers for this thread. We need to get
343 * libcrypto to tell us about later thread stop events. c_thread_start
344 * is a callback to libcrypto defined in fipsprov.c
346 if (!c_thread_start(FIPS_get_provider(ctx), ossl_ctx_thread_stop))
351 hand = OPENSSL_malloc(sizeof(*hand));
355 hand->handfn = handfn;
365 static int init_thread_deregister(void *index, int all)
367 GLOBAL_TEVENT_REGISTER *gtr;
370 gtr = get_global_tevent_register();
372 CRYPTO_THREAD_write_lock(gtr->lock);
373 for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
374 THREAD_EVENT_HANDLER **hands
375 = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
376 THREAD_EVENT_HANDLER *curr = *hands, *prev = NULL, *tmp;
380 CRYPTO_THREAD_unlock(gtr->lock);
383 while (curr != NULL) {
384 if (all || curr->index == index) {
386 prev->next = curr->next;
401 CRYPTO_THREAD_lock_free(gtr->lock);
402 sk_THREAD_EVENT_HANDLER_PTR_free(gtr->skhands);
405 CRYPTO_THREAD_unlock(gtr->lock);
410 int ossl_init_thread_deregister(void *index)
412 return init_thread_deregister(index, 0);