Deprecate most of debug-memory
[openssl.git] / crypto / ex_data.c
1 /*
2  * Copyright 1995-2018 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 "crypto/cryptlib.h"
11 #include "internal/thread_once.h"
12
13 int do_ex_data_init(OPENSSL_CTX *ctx)
14 {
15     OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
16
17     if (global == NULL)
18         return 0;
19
20     global->ex_data_lock = CRYPTO_THREAD_lock_new();
21     return global->ex_data_lock != NULL;
22 }
23
24 /*
25  * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
26  * a given class.  On success, *holds the lock.*
27  */
28 static EX_CALLBACKS *get_and_lock(OPENSSL_CTX *ctx, int class_index)
29 {
30     EX_CALLBACKS *ip;
31     OSSL_EX_DATA_GLOBAL *global = NULL;
32
33     if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
34         CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_PASSED_INVALID_ARGUMENT);
35         return NULL;
36     }
37
38     global = openssl_ctx_get_ex_data_global(ctx);
39     if (global == NULL || global->ex_data_lock == NULL) {
40         /*
41          * If we get here, someone (who?) cleaned up the lock, so just
42          * treat it as an error.
43          */
44          return NULL;
45     }
46
47     CRYPTO_THREAD_write_lock(global->ex_data_lock);
48     ip = &global->ex_data[class_index];
49     return ip;
50 }
51
52 static void cleanup_cb(EX_CALLBACK *funcs)
53 {
54     OPENSSL_free(funcs);
55 }
56
57 /*
58  * Release all "ex_data" state to prevent memory leaks. This can't be made
59  * thread-safe without overhauling a lot of stuff, and shouldn't really be
60  * called under potential race-conditions anyway (it's for program shutdown
61  * after all).
62  */
63 void crypto_cleanup_all_ex_data_int(OPENSSL_CTX *ctx)
64 {
65     int i;
66     OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
67
68     if (global == NULL)
69         return;
70
71     for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
72         EX_CALLBACKS *ip = &global->ex_data[i];
73
74         sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
75         ip->meth = NULL;
76     }
77
78     CRYPTO_THREAD_lock_free(global->ex_data_lock);
79     global->ex_data_lock = NULL;
80 }
81
82
83 /*
84  * Unregister a new index by replacing the callbacks with no-ops.
85  * Any in-use instances are leaked.
86  */
87 static void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
88                      long argl, void *argp)
89 {
90 }
91
92 static void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
93                        long argl, void *argp)
94 {
95 }
96
97 static int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
98                      void *from_d, int idx,
99                      long argl, void *argp)
100 {
101     return 1;
102 }
103
104 int crypto_free_ex_index_ex(OPENSSL_CTX *ctx, int class_index, int idx)
105 {
106     EX_CALLBACKS *ip;
107     EX_CALLBACK *a;
108     int toret = 0;
109     OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
110
111     if (global == NULL)
112         return 0;
113
114     ip = get_and_lock(ctx, class_index);
115     if (ip == NULL)
116         return 0;
117     if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
118         goto err;
119     a = sk_EX_CALLBACK_value(ip->meth, idx);
120     if (a == NULL)
121         goto err;
122     a->new_func = dummy_new;
123     a->dup_func = dummy_dup;
124     a->free_func = dummy_free;
125     toret = 1;
126 err:
127     CRYPTO_THREAD_unlock(global->ex_data_lock);
128     return toret;
129 }
130
131 int CRYPTO_free_ex_index(int class_index, int idx)
132 {
133     return crypto_free_ex_index_ex(NULL, class_index, idx);
134 }
135
136 /*
137  * Register a new index.
138  */
139 int crypto_get_ex_new_index_ex(OPENSSL_CTX *ctx, int class_index, long argl,
140                                void *argp, CRYPTO_EX_new *new_func,
141                                CRYPTO_EX_dup *dup_func,
142                                CRYPTO_EX_free *free_func)
143 {
144     int toret = -1;
145     EX_CALLBACK *a;
146     EX_CALLBACKS *ip;
147     OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
148
149     if (global == NULL)
150         return -1;
151
152     ip = get_and_lock(ctx, class_index);
153     if (ip == NULL)
154         return -1;
155
156     if (ip->meth == NULL) {
157         ip->meth = sk_EX_CALLBACK_new_null();
158         /* We push an initial value on the stack because the SSL
159          * "app_data" routines use ex_data index zero.  See RT 3710. */
160         if (ip->meth == NULL
161             || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
162             CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX, ERR_R_MALLOC_FAILURE);
163             goto err;
164         }
165     }
166
167     a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
168     if (a == NULL) {
169         CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX, ERR_R_MALLOC_FAILURE);
170         goto err;
171     }
172     a->argl = argl;
173     a->argp = argp;
174     a->new_func = new_func;
175     a->dup_func = dup_func;
176     a->free_func = free_func;
177
178     if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
179         CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX_EX, ERR_R_MALLOC_FAILURE);
180         OPENSSL_free(a);
181         goto err;
182     }
183     toret = sk_EX_CALLBACK_num(ip->meth) - 1;
184     (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
185
186  err:
187     CRYPTO_THREAD_unlock(global->ex_data_lock);
188     return toret;
189 }
190
191 int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
192                             CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
193                             CRYPTO_EX_free *free_func)
194 {
195     return crypto_get_ex_new_index_ex(NULL, class_index, argl, argp, new_func,
196                                       dup_func, free_func);
197 }
198
199 /*
200  * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
201  * calling new() callbacks for each index in the class used by this variable
202  * Thread-safe by copying a class's array of "EX_CALLBACK" entries
203  * in the lock, then using them outside the lock. Note this only applies
204  * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
205  */
206 int crypto_new_ex_data_ex(OPENSSL_CTX *ctx, int class_index, void *obj,
207                           CRYPTO_EX_DATA *ad)
208 {
209     int mx, i;
210     void *ptr;
211     EX_CALLBACK **storage = NULL;
212     EX_CALLBACK *stack[10];
213     EX_CALLBACKS *ip;
214     OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ctx);
215
216     if (global == NULL)
217         return 0;
218
219     ip = get_and_lock(ctx, class_index);
220     if (ip == NULL)
221         return 0;
222
223     ad->ctx = ctx;
224     ad->sk = NULL;
225
226     mx = sk_EX_CALLBACK_num(ip->meth);
227     if (mx > 0) {
228         if (mx < (int)OSSL_NELEM(stack))
229             storage = stack;
230         else
231             storage = OPENSSL_malloc(sizeof(*storage) * mx);
232         if (storage != NULL)
233             for (i = 0; i < mx; i++)
234                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
235     }
236     CRYPTO_THREAD_unlock(global->ex_data_lock);
237
238     if (mx > 0 && storage == NULL) {
239         CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA_EX, ERR_R_MALLOC_FAILURE);
240         return 0;
241     }
242     for (i = 0; i < mx; i++) {
243         if (storage[i] != NULL && storage[i]->new_func != NULL) {
244             ptr = CRYPTO_get_ex_data(ad, i);
245             storage[i]->new_func(obj, ptr, ad, i,
246                                  storage[i]->argl, storage[i]->argp);
247         }
248     }
249     if (storage != stack)
250         OPENSSL_free(storage);
251     return 1;
252 }
253
254 int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
255 {
256     return crypto_new_ex_data_ex(NULL, class_index, obj, ad);
257 }
258
259 /*
260  * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
261  * for each index in the class used by this variable
262  */
263 int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
264                        const CRYPTO_EX_DATA *from)
265 {
266     int mx, j, i;
267     void *ptr;
268     EX_CALLBACK *stack[10];
269     EX_CALLBACK **storage = NULL;
270     EX_CALLBACKS *ip;
271     int toret = 0;
272     OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(from->ctx);
273
274     if (global == NULL)
275         return 0;
276
277     to->ctx = from->ctx;
278     if (from->sk == NULL)
279         /* Nothing to copy over */
280         return 1;
281     if ((ip = get_and_lock(from->ctx, class_index)) == NULL)
282         return 0;
283
284     mx = sk_EX_CALLBACK_num(ip->meth);
285     j = sk_void_num(from->sk);
286     if (j < mx)
287         mx = j;
288     if (mx > 0) {
289         if (mx < (int)OSSL_NELEM(stack))
290             storage = stack;
291         else
292             storage = OPENSSL_malloc(sizeof(*storage) * mx);
293         if (storage != NULL)
294             for (i = 0; i < mx; i++)
295                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
296     }
297     CRYPTO_THREAD_unlock(global->ex_data_lock);
298
299     if (mx == 0)
300         return 1;
301     if (storage == NULL) {
302         CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
303         return 0;
304     }
305     /*
306      * Make sure the ex_data stack is at least |mx| elements long to avoid
307      * issues in the for loop that follows; so go get the |mx|'th element
308      * (if it does not exist CRYPTO_get_ex_data() returns NULL), and assign
309      * to itself. This is normally a no-op; but ensures the stack is the
310      * proper size
311      */
312     if (!CRYPTO_set_ex_data(to, mx - 1, CRYPTO_get_ex_data(to, mx - 1)))
313         goto err;
314
315     for (i = 0; i < mx; i++) {
316         ptr = CRYPTO_get_ex_data(from, i);
317         if (storage[i] != NULL && storage[i]->dup_func != NULL)
318             if (!storage[i]->dup_func(to, from, &ptr, i,
319                                       storage[i]->argl, storage[i]->argp))
320                 goto err;
321         CRYPTO_set_ex_data(to, i, ptr);
322     }
323     toret = 1;
324  err:
325     if (storage != stack)
326         OPENSSL_free(storage);
327     return toret;
328 }
329
330
331 /*
332  * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
333  * each index in the class used by this variable
334  */
335 void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
336 {
337     int mx, i;
338     EX_CALLBACKS *ip;
339     void *ptr;
340     EX_CALLBACK *f;
341     EX_CALLBACK *stack[10];
342     EX_CALLBACK **storage = NULL;
343     OSSL_EX_DATA_GLOBAL *global;
344
345     if ((ip = get_and_lock(ad->ctx, class_index)) == NULL)
346         goto err;
347     global = openssl_ctx_get_ex_data_global(ad->ctx);
348     if (global == NULL)
349         goto err;
350
351     mx = sk_EX_CALLBACK_num(ip->meth);
352     if (mx > 0) {
353         if (mx < (int)OSSL_NELEM(stack))
354             storage = stack;
355         else
356             storage = OPENSSL_malloc(sizeof(*storage) * mx);
357         if (storage != NULL)
358             for (i = 0; i < mx; i++)
359                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
360     }
361     CRYPTO_THREAD_unlock(global->ex_data_lock);
362
363     for (i = 0; i < mx; i++) {
364         if (storage != NULL)
365             f = storage[i];
366         else {
367             CRYPTO_THREAD_write_lock(global->ex_data_lock);
368             f = sk_EX_CALLBACK_value(ip->meth, i);
369             CRYPTO_THREAD_unlock(global->ex_data_lock);
370         }
371         if (f != NULL && f->free_func != NULL) {
372             ptr = CRYPTO_get_ex_data(ad, i);
373             f->free_func(obj, ptr, ad, i, f->argl, f->argp);
374         }
375     }
376
377     if (storage != stack)
378         OPENSSL_free(storage);
379  err:
380     sk_void_free(ad->sk);
381     ad->sk = NULL;
382     ad->ctx = NULL;
383 }
384
385 /*
386  * Allocate a given CRYPTO_EX_DATA item using the class specific allocation
387  * function
388  */
389 int CRYPTO_alloc_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad,
390                          int idx)
391 {
392     EX_CALLBACK *f;
393     EX_CALLBACKS *ip;
394     void *curval;
395     OSSL_EX_DATA_GLOBAL *global = openssl_ctx_get_ex_data_global(ad->ctx);
396
397     if (global == NULL)
398         return 0;
399
400     curval = CRYPTO_get_ex_data(ad, idx);
401
402     /* Already there, no need to allocate */
403     if (curval != NULL)
404         return 1;
405
406     ip = get_and_lock(ad->ctx, class_index);
407     if (ip == NULL)
408         return 0;
409     f = sk_EX_CALLBACK_value(ip->meth, idx);
410     CRYPTO_THREAD_unlock(global->ex_data_lock);
411
412     /*
413      * This should end up calling CRYPTO_set_ex_data(), which allocates
414      * everything necessary to support placing the new data in the right spot.
415      */
416     if (f->new_func == NULL)
417         return 0;
418
419     f->new_func(obj, NULL, ad, idx, f->argl, f->argp);
420
421     return 1;
422 }
423
424 /*
425  * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
426  * particular index in the class used by this variable
427  */
428 int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
429 {
430     int i;
431
432     if (ad->sk == NULL) {
433         if ((ad->sk = sk_void_new_null()) == NULL) {
434             CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
435             return 0;
436         }
437     }
438
439     for (i = sk_void_num(ad->sk); i <= idx; ++i) {
440         if (!sk_void_push(ad->sk, NULL)) {
441             CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
442             return 0;
443         }
444     }
445     sk_void_set(ad->sk, idx, val);
446     return 1;
447 }
448
449 /*
450  * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
451  * particular index in the class used by this variable
452  */
453 void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
454 {
455     if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
456         return NULL;
457     return sk_void_value(ad->sk, idx);
458 }
459
460 OPENSSL_CTX *crypto_ex_data_get_openssl_ctx(const CRYPTO_EX_DATA *ad)
461 {
462     return ad->ctx;
463 }