Clean away unnecessary length related OSSL_PARAM key names
[openssl.git] / crypto / initthread.c
1 /*
2  * Copyright 2019-2020 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_dispatch.h>
12 #include "crypto/cryptlib.h"
13 #include "prov/providercommon.h"
14 #include "internal/thread_once.h"
15
16 #ifdef FIPS_MODULE
17 #include "prov/provider_ctx.h"
18
19 /*
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.
26  *
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).
30  */
31 extern OSSL_FUNC_core_thread_start_fn *c_thread_start;
32 #endif
33
34 typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
35 struct thread_event_handler_st {
36     const void *index;
37     void *arg;
38     OSSL_thread_stop_handler_fn handfn;
39     THREAD_EVENT_HANDLER *next;
40 };
41
42 #ifndef FIPS_MODULE
43 DEFINE_SPECIAL_STACK_OF(THREAD_EVENT_HANDLER_PTR, THREAD_EVENT_HANDLER *)
44
45 typedef struct global_tevent_register_st GLOBAL_TEVENT_REGISTER;
46 struct global_tevent_register_st {
47     STACK_OF(THREAD_EVENT_HANDLER_PTR) *skhands;
48     CRYPTO_RWLOCK *lock;
49 };
50
51 static GLOBAL_TEVENT_REGISTER *glob_tevent_reg = NULL;
52
53 static CRYPTO_ONCE tevent_register_runonce = CRYPTO_ONCE_STATIC_INIT;
54
55 DEFINE_RUN_ONCE_STATIC(create_global_tevent_register)
56 {
57     glob_tevent_reg = OPENSSL_zalloc(sizeof(*glob_tevent_reg));
58     if (glob_tevent_reg == NULL)
59         return 0;
60
61     glob_tevent_reg->skhands = sk_THREAD_EVENT_HANDLER_PTR_new_null();
62     glob_tevent_reg->lock = CRYPTO_THREAD_lock_new();
63     if (glob_tevent_reg->skhands == NULL || glob_tevent_reg->lock == NULL) {
64         sk_THREAD_EVENT_HANDLER_PTR_free(glob_tevent_reg->skhands);
65         CRYPTO_THREAD_lock_free(glob_tevent_reg->lock);
66         OPENSSL_free(glob_tevent_reg);
67         glob_tevent_reg = NULL;
68         return 0;
69     }
70
71     return 1;
72 }
73
74 static GLOBAL_TEVENT_REGISTER *get_global_tevent_register(void)
75 {
76     if (!RUN_ONCE(&tevent_register_runonce, create_global_tevent_register))
77         return NULL;
78     return glob_tevent_reg;
79 }
80 #endif
81
82 #ifndef FIPS_MODULE
83 static int  init_thread_push_handlers(THREAD_EVENT_HANDLER **hands);
84 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin);
85 static void init_thread_destructor(void *hands);
86 static int  init_thread_deregister(void *arg, int all);
87 #endif
88 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
89
90 static THREAD_EVENT_HANDLER **
91 init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
92 {
93     THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local(local);
94
95     if (alloc) {
96         if (hands == NULL) {
97
98             if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL)
99                 return NULL;
100
101             if (!CRYPTO_THREAD_set_local(local, hands)) {
102                 OPENSSL_free(hands);
103                 return NULL;
104             }
105
106 #ifndef FIPS_MODULE
107             if (!init_thread_push_handlers(hands)) {
108                 CRYPTO_THREAD_set_local(local, NULL);
109                 OPENSSL_free(hands);
110                 return NULL;
111             }
112 #endif
113         }
114     } else if (!keep) {
115         CRYPTO_THREAD_set_local(local, NULL);
116     }
117
118     return hands;
119 }
120
121 #ifndef FIPS_MODULE
122 /*
123  * Since per-thread-specific-data destructors are not universally
124  * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
125  * is assumed to have destructor associated. And then an effort is made
126  * to call this single destructor on non-pthread platform[s].
127  *
128  * Initial value is "impossible". It is used as guard value to shortcut
129  * destructor for threads terminating before libcrypto is initialized or
130  * after it's de-initialized. Access to the key doesn't have to be
131  * serialized for the said threads, because they didn't use libcrypto
132  * and it doesn't matter if they pick "impossible" or dereference real
133  * key value and pull NULL past initialization in the first thread that
134  * intends to use libcrypto.
135  */
136 static union {
137     long sane;
138     CRYPTO_THREAD_LOCAL value;
139 } destructor_key = { -1 };
140
141 /*
142  * The thread event handler list is a thread specific linked list
143  * of callback functions which are invoked in list order by the
144  * current thread in case of certain events. (Currently, there is
145  * only one type of event, the 'thread stop' event.)
146  *
147  * We also keep a global reference to that linked list, so that we
148  * can deregister handlers if necessary before all the threads are
149  * stopped.
150  */
151 static int init_thread_push_handlers(THREAD_EVENT_HANDLER **hands)
152 {
153     int ret;
154     GLOBAL_TEVENT_REGISTER *gtr;
155
156     gtr = get_global_tevent_register();
157     if (gtr == NULL)
158         return 0;
159
160     CRYPTO_THREAD_write_lock(gtr->lock);
161     ret = (sk_THREAD_EVENT_HANDLER_PTR_push(gtr->skhands, hands) != 0);
162     CRYPTO_THREAD_unlock(gtr->lock);
163
164     return ret;
165 }
166
167 static void init_thread_remove_handlers(THREAD_EVENT_HANDLER **handsin)
168 {
169     GLOBAL_TEVENT_REGISTER *gtr;
170     int i;
171
172     gtr = get_global_tevent_register();
173     if (gtr == NULL)
174         return;
175     CRYPTO_THREAD_write_lock(gtr->lock);
176     for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
177         THREAD_EVENT_HANDLER **hands
178             = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
179
180         if (hands == handsin) {
181             sk_THREAD_EVENT_HANDLER_PTR_delete(gtr->skhands, i);
182             CRYPTO_THREAD_unlock(gtr->lock);
183             return;
184         }
185     }
186     CRYPTO_THREAD_unlock(gtr->lock);
187     return;
188 }
189
190 static void init_thread_destructor(void *hands)
191 {
192     init_thread_stop(NULL, (THREAD_EVENT_HANDLER **)hands);
193     init_thread_remove_handlers(hands);
194     OPENSSL_free(hands);
195 }
196
197 int ossl_init_thread(void)
198 {
199     if (!CRYPTO_THREAD_init_local(&destructor_key.value,
200                                   init_thread_destructor))
201         return 0;
202
203     return 1;
204 }
205
206 void ossl_cleanup_thread(void)
207 {
208     init_thread_deregister(NULL, 1);
209     CRYPTO_THREAD_cleanup_local(&destructor_key.value);
210     destructor_key.sane = -1;
211 }
212
213 void OPENSSL_thread_stop_ex(OSSL_LIB_CTX *ctx)
214 {
215     ctx = ossl_lib_ctx_get_concrete(ctx);
216     /*
217      * TODO(3.0). It would be nice if we could figure out a way to do this on
218      * all threads that have used the OSSL_LIB_CTX when the context is freed.
219      * This is currently not possible due to the use of thread local variables.
220      */
221     ossl_ctx_thread_stop(ctx);
222 }
223
224 void OPENSSL_thread_stop(void)
225 {
226     if (destructor_key.sane != -1) {
227         THREAD_EVENT_HANDLER **hands
228             = init_get_thread_local(&destructor_key.value, 0, 0);
229         init_thread_stop(NULL, hands);
230
231         init_thread_remove_handlers(hands);
232         OPENSSL_free(hands);
233     }
234 }
235
236 void ossl_ctx_thread_stop(void *arg)
237 {
238     if (destructor_key.sane != -1) {
239         THREAD_EVENT_HANDLER **hands
240             = init_get_thread_local(&destructor_key.value, 0, 1);
241         init_thread_stop(arg, hands);
242     }
243 }
244
245 #else
246
247 static void *thread_event_ossl_ctx_new(OSSL_LIB_CTX *libctx)
248 {
249     THREAD_EVENT_HANDLER **hands = NULL;
250     CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
251
252     if (tlocal == NULL)
253         return NULL;
254
255     if (!CRYPTO_THREAD_init_local(tlocal,  NULL)) {
256         goto err;
257     }
258
259     hands = OPENSSL_zalloc(sizeof(*hands));
260     if (hands == NULL)
261         goto err;
262
263     if (!CRYPTO_THREAD_set_local(tlocal, hands))
264         goto err;
265
266     return tlocal;
267  err:
268     OPENSSL_free(hands);
269     OPENSSL_free(tlocal);
270     return NULL;
271 }
272
273 static void thread_event_ossl_ctx_free(void *tlocal)
274 {
275     OPENSSL_free(tlocal);
276 }
277
278 static const OSSL_LIB_CTX_METHOD thread_event_ossl_ctx_method = {
279     thread_event_ossl_ctx_new,
280     thread_event_ossl_ctx_free,
281 };
282
283 void ossl_ctx_thread_stop(void *arg)
284 {
285     THREAD_EVENT_HANDLER **hands;
286     OSSL_LIB_CTX *ctx = PROV_LIBCTX_OF(arg);
287     CRYPTO_THREAD_LOCAL *local
288         = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX,
289                                 &thread_event_ossl_ctx_method);
290
291     if (local == NULL)
292         return;
293     hands = init_get_thread_local(local, 0, 0);
294     init_thread_stop(ctx, hands);
295     OPENSSL_free(hands);
296 }
297 #endif /* FIPS_MODULE */
298
299
300 static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands)
301 {
302     THREAD_EVENT_HANDLER *curr, *prev = NULL, *tmp;
303
304     /* Can't do much about this */
305     if (hands == NULL)
306         return;
307
308     curr = *hands;
309     while (curr != NULL) {
310         if (arg != NULL && curr->arg != arg) {
311             prev = curr;
312             curr = curr->next;
313             continue;
314         }
315         curr->handfn(curr->arg);
316         if (prev == NULL)
317             *hands = curr->next;
318         else
319             prev->next = curr->next;
320
321         tmp = curr;
322         curr = curr->next;
323
324         OPENSSL_free(tmp);
325     }
326 }
327
328 int ossl_init_thread_start(const void *index, void *arg,
329                            OSSL_thread_stop_handler_fn handfn)
330 {
331     THREAD_EVENT_HANDLER **hands;
332     THREAD_EVENT_HANDLER *hand;
333 #ifdef FIPS_MODULE
334     OSSL_LIB_CTX *ctx = arg;
335
336     /*
337      * In FIPS mode the list of THREAD_EVENT_HANDLERs is unique per combination
338      * of OSSL_LIB_CTX and thread. This is because in FIPS mode each
339      * OSSL_LIB_CTX gets informed about thread stop events individually.
340      */
341     CRYPTO_THREAD_LOCAL *local
342         = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX,
343                                 &thread_event_ossl_ctx_method);
344 #else
345     /*
346      * Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
347      * thread, but may hold multiple OSSL_LIB_CTXs. We only get told about
348      * thread stop events globally, so we have to ensure all affected
349      * OSSL_LIB_CTXs are informed.
350      */
351     CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
352 #endif
353
354     hands = init_get_thread_local(local, 1, 0);
355     if (hands == NULL)
356         return 0;
357
358 #ifdef FIPS_MODULE
359     if (*hands == NULL) {
360         /*
361          * We've not yet registered any handlers for this thread. We need to get
362          * libcrypto to tell us about later thread stop events. c_thread_start
363          * is a callback to libcrypto defined in fipsprov.c
364          */
365         if (!c_thread_start(FIPS_get_core_handle(ctx), ossl_ctx_thread_stop))
366             return 0;
367     }
368 #endif
369
370     hand = OPENSSL_malloc(sizeof(*hand));
371     if (hand == NULL)
372         return 0;
373
374     hand->handfn = handfn;
375     hand->arg = arg;
376     hand->index = index;
377     hand->next = *hands;
378     *hands = hand;
379
380     return 1;
381 }
382
383 #ifndef FIPS_MODULE
384 static int init_thread_deregister(void *index, int all)
385 {
386     GLOBAL_TEVENT_REGISTER *gtr;
387     int i;
388
389     gtr = get_global_tevent_register();
390     if (gtr == NULL)
391         return 0;
392     if (!all)
393         CRYPTO_THREAD_write_lock(gtr->lock);
394     else
395         glob_tevent_reg = NULL;
396     for (i = 0; i < sk_THREAD_EVENT_HANDLER_PTR_num(gtr->skhands); i++) {
397         THREAD_EVENT_HANDLER **hands
398             = sk_THREAD_EVENT_HANDLER_PTR_value(gtr->skhands, i);
399         THREAD_EVENT_HANDLER *curr = NULL, *prev = NULL, *tmp;
400
401         if (hands == NULL) {
402             if (!all)
403                 CRYPTO_THREAD_unlock(gtr->lock);
404             return 0;
405         }
406         curr = *hands;
407         while (curr != NULL) {
408             if (all || curr->index == index) {
409                 if (prev != NULL)
410                     prev->next = curr->next;
411                 else
412                     *hands = curr->next;
413                 tmp = curr;
414                 curr = curr->next;
415                 OPENSSL_free(tmp);
416                 continue;
417             }
418             prev = curr;
419             curr = curr->next;
420         }
421         if (all)
422             OPENSSL_free(hands);
423     }
424     if (all) {
425         CRYPTO_THREAD_lock_free(gtr->lock);
426         sk_THREAD_EVENT_HANDLER_PTR_free(gtr->skhands);
427         OPENSSL_free(gtr);
428     } else {
429         CRYPTO_THREAD_unlock(gtr->lock);
430     }
431     return 1;
432 }
433
434 int ossl_init_thread_deregister(void *index)
435 {
436     return init_thread_deregister(index, 0);
437 }
438 #endif