b398b05cd21c0c3fa137e47c7dae220c56ee135e
[openssl.git] / crypto / initthread.c
1 /*
2  * Copyright 2019 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_numbers.h>
12 #include "internal/cryptlib_int.h"
13 #include "internal/providercommon.h"
14 #include "internal/thread_once.h"
15
16 #ifdef FIPS_MODE
17 /*
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.
24  * 
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).
28  */
29 extern OSSL_core_thread_start_fn *c_thread_start;
30 #endif
31
32 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
33 struct thread_event_handler_st {
34     const void *index;
35     void *arg;
36     OSSL_thread_stop_handler_fn handfn;
37     THREAD_EVENT_HANDLER *next;
38 };
39
40 #ifndef FIPS_MODE
41 DEFINE_SPECIAL_STACK_OF(THREAD_EVENT_HANDLER_PTR, THREAD_EVENT_HANDLER *)
42
43 typedef struct global_tevent_register_st GLOBAL_TEVENT_REGISTER;
44 struct global_tevent_register_st {
45     STACK_OF(THREAD_EVENT_HANDLER_PTR) *skhands;
46     CRYPTO_RWLOCK *lock;
47 };
48
49 static GLOBAL_TEVENT_REGISTER *glob_tevent_reg = NULL;
50
51 static CRYPTO_ONCE tevent_register_runonce = CRYPTO_ONCE_STATIC_INIT;
52
53 DEFINE_RUN_ONCE_STATIC(create_global_tevent_register)
54 {
55     glob_tevent_reg = OPENSSL_zalloc(sizeof(*glob_tevent_reg));
56     if (glob_tevent_reg == NULL)
57         return 0;
58
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;
66         return 0;
67     }
68
69     return 1;
70 }
71
72 static GLOBAL_TEVENT_REGISTER *get_global_tevent_register(void)
73 {
74     if (!RUN_ONCE(&tevent_register_runonce, create_global_tevent_register))
75         return NULL;
76     return glob_tevent_reg;
77 }
78 #endif
79
80 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
81
82 static THREAD_EVENT_HANDLER **
83 init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
84 {
85     THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local);
86
87     if (alloc) {
88         if (hands == NULL) {
89 #ifndef FIPS_MODE
90             GLOBAL_TEVENT_REGISTER *gtr;
91 #endif
92
93             if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL) {
94                 OPENSSL_free(hands);
95                 return NULL;
96             }
97
98 #ifndef FIPS_MODE
99             /*
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.
105              */
106             gtr = get_global_tevent_register();
107             if (gtr == NULL) {
108                 OPENSSL_free(hands);
109                 return NULL;
110             }
111             CRYPTO_THREAD_write_lock(gtr->lock);
112             if (!sk_THREAD_EVENT_HANDLER_PTR_push(gtr->skhands, hands)) {
113                 OPENSSL_free(hands);
114                 CRYPTO_THREAD_unlock(gtr->lock);
115                 return NULL;
116             }
117             CRYPTO_THREAD_unlock(gtr->lock);
118 #endif
119             if (!CRYPTO_THREAD_set_local(local, hands)) {
120                 OPENSSL_free(hands);
121                 return NULL;
122             }
123         }
124     } else if (!keep) {
125         CRYPTO_THREAD_set_local(local, NULL);
126     }
127
128     return hands;
129 }
130
131 #ifndef FIPS_MODE
132 /*
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].
137  *
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 derefernce real
143  * key value and pull NULL past initialization in the first thread that
144  * intends to use libcrypto.
145  */
146 static union {
147     long sane;
148     CRYPTO_THREAD_LOCAL value;
149 } destructor_key = { -1 };
150
151 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin)
152 {
153     GLOBAL_TEVENT_REGISTER *gtr;
154     int i;
155
156     gtr = get_global_tevent_register();
157     if (gtr == NULL)
158         return;
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);
163
164         if (hands == handsin) {
165             hands = sk_THREAD_EVENT_HANDLER_PTR_delete(gtr->skhands, i);
166             CRYPTO_THREAD_unlock(gtr->lock);
167             return;
168         }
169     }
170     CRYPTO_THREAD_unlock(gtr->lock);
171     return;
172 }
173
174 static void init_thread_destructor(void *hands)
175 {
176     init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands);
177     init_thread_remove_handlers(hands);
178     OPENSSL_free(hands);
179 }
180
181 int ossl_init_thread(void)
182 {
183     if (!CRYPTO_THREAD_init_local(&destructor_key.value,
184                                   init_thread_destructor))
185         return 0;
186
187     return 1;
188 }
189
190 static int init_thread_deregister(void *arg, int all);
191
192 void ossl_cleanup_thread(void)
193 {
194     init_thread_deregister(NULL, 1);
195     CRYPTO_THREAD_cleanup_local(&destructor_key.value);
196     destructor_key.sane = -1;
197 }
198
199 void OPENSSL_thread_stop_ex(OPENSSL_CTX *ctx)
200 {
201     ctx = openssl_ctx_get_concrete(ctx);
202     /*
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.
206      */
207     ossl_ctx_thread_stop(ctx);
208 }
209
210 void OPENSSL_thread_stop(void)
211 {
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);
216
217         init_thread_remove_handlers(hands);
218         OPENSSL_free(hands);
219     }
220 }
221
222 void ossl_ctx_thread_stop(void *arg)
223 {
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);
228     }
229 }
230
231 #else
232
233 static void *thread_event_ossl_ctx_new(OPENSSL_CTX *libctx)
234 {
235     THREAD_EVENT_HANDLER **hands = NULL;
236     CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
237
238     if (tlocal == NULL)
239         return NULL;
240
241     if (!CRYPTO_THREAD_init_local(tlocal,  NULL)) {
242         goto err;
243     }
244
245     hands = OPENSSL_zalloc(sizeof(*hands));
246     if (hands == NULL)
247         goto err;
248
249     if (!CRYPTO_THREAD_set_local(tlocal, hands))
250         goto err;
251
252     return tlocal;
253  err:
254     OPENSSL_free(hands);
255     OPENSSL_free(tlocal);
256     return NULL;
257 }
258
259 static void thread_event_ossl_ctx_free(void *tlocal)
260 {
261     OPENSSL_free(tlocal);
262 }
263
264 static const OPENSSL_CTX_METHOD thread_event_ossl_ctx_method = {
265     thread_event_ossl_ctx_new,
266     thread_event_ossl_ctx_free,
267 };
268
269 void ossl_ctx_thread_stop(void *arg)
270 {
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);
276
277     if (local == NULL)
278         return;
279     hands = init_get_thread_local(local, 0, 0);
280     init_thread_stop(arg, hands);
281     OPENSSL_free(hands);
282 }
283 #endif /* FIPS_MODE */
284
285
286 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands)
287 {
288     THREAD_EVENT_HANDLER *curr, *prev = NULL;
289
290     /* Can't do much about this */
291     if (hands == NULL)
292         return;
293
294     curr = *hands;
295     while (curr != NULL) {
296         if (arg != NULL && curr->arg != arg) {
297             curr = curr->next;
298             continue;
299         }
300         curr->handfn(curr->arg);
301         prev = curr;
302         curr = curr->next;
303         if (prev == *hands)
304             *hands = curr;
305         OPENSSL_free(prev);
306     }
307 }
308
309 int ossl_init_thread_start(const void *index, void *arg,
310                            OSSL_thread_stop_handler_fn handfn)
311 {
312     THREAD_EVENT_HANDLER **hands;
313     THREAD_EVENT_HANDLER *hand;
314 #ifdef FIPS_MODE
315     OPENSSL_CTX *ctx = arg;
316
317     /*
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.
321      */
322     CRYPTO_THREAD_LOCAL *local
323         = openssl_ctx_get_data(ctx, OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX,
324                                &thread_event_ossl_ctx_method);
325 #else
326     /*
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.
331      */
332     CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
333 #endif
334
335     hands = init_get_thread_local(local, 1, 0);
336     if (hands == NULL)
337         return 0;
338
339 #ifdef FIPS_MODE
340     if (*hands == NULL) {
341         /*
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
345          */
346         if (!c_thread_start(FIPS_get_provider(ctx), ossl_ctx_thread_stop))
347             return 0;
348     }
349 #endif
350
351     hand = OPENSSL_malloc(sizeof(*hand));
352     if (hand == NULL)
353         return 0;
354
355     hand->handfn = handfn;
356     hand->arg = arg;
357     hand->index = index;
358     hand->next = *hands;
359     *hands = hand;
360
361     return 1;
362 }
363
364 #ifndef FIPS_MODE
365 static int init_thread_deregister(void *index, int all)
366 {
367     GLOBAL_TEVENT_REGISTER *gtr;
368     int i;
369
370     gtr = get_global_tevent_register();
371     if (!all)
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;
377
378         if (hands == NULL) {
379             if (!all)
380                 CRYPTO_THREAD_unlock(gtr->lock);
381             return 0;
382         }
383         while (curr != NULL) {
384             if (all || curr->index == index) {
385                 if (prev != NULL)
386                     prev->next = curr->next;
387                 else
388                     *hands = curr->next;
389                 tmp = curr;
390                 curr = curr->next;
391                 OPENSSL_free(tmp);
392                 continue;
393             }
394             prev = curr;
395             curr = curr->next;
396         }
397         if (all)
398             OPENSSL_free(hands);
399     }
400     if (all) {
401         CRYPTO_THREAD_lock_free(gtr->lock);
402         sk_THREAD_EVENT_HANDLER_PTR_free(gtr->skhands);
403         OPENSSL_free(gtr);
404     } else {
405         CRYPTO_THREAD_unlock(gtr->lock);
406     }
407     return 1;
408 }
409
410 int ossl_init_thread_deregister(void *index)
411 {
412     return init_thread_deregister(index, 0);
413 }
414 #endif