Ignore all .a files, not just the top ones
[openssl.git] / crypto / ex_data.c
1 /*
2  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (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 "internal/cryptlib_int.h"
11 #include "internal/thread_once.h"
12 #include <openssl/lhash.h>
13
14 /*
15  * Each structure type (sometimes called a class), that supports
16  * exdata has a stack of callbacks for each instance.
17  */
18 struct ex_callback_st {
19     long argl;                  /* Arbitrary long */
20     void *argp;                 /* Arbitrary void * */
21     CRYPTO_EX_new *new_func;
22     CRYPTO_EX_free *free_func;
23     CRYPTO_EX_dup *dup_func;
24 };
25
26 /*
27  * The state for each class.  This could just be a typedef, but
28  * a structure allows future changes.
29  */
30 typedef struct ex_callbacks_st {
31     STACK_OF(EX_CALLBACK) *meth;
32 } EX_CALLBACKS;
33
34 static EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT];
35
36 static CRYPTO_RWLOCK *ex_data_lock = NULL;
37 static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT;
38
39 DEFINE_RUN_ONCE_STATIC(do_ex_data_init)
40 {
41     OPENSSL_init_crypto(0, NULL);
42     ex_data_lock = CRYPTO_THREAD_lock_new();
43     return ex_data_lock != NULL;
44 }
45
46 /*
47  * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
48  * a given class.  On success, *holds the lock.*
49  */
50 static EX_CALLBACKS *get_and_lock(int class_index)
51 {
52     EX_CALLBACKS *ip;
53
54     if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
55         CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_PASSED_INVALID_ARGUMENT);
56         return NULL;
57     }
58
59     if (!RUN_ONCE(&ex_data_init, do_ex_data_init)) {
60         CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE);
61         return NULL;
62     }
63
64     if (ex_data_lock == NULL) {
65         /*
66          * This can happen in normal operation when using CRYPTO_mem_leaks().
67          * The CRYPTO_mem_leaks() function calls OPENSSL_cleanup() which cleans
68          * up the locks. Subsequently the BIO that CRYPTO_mem_leaks() uses gets
69          * freed, which also attempts to free the ex_data. However
70          * CRYPTO_mem_leaks() ensures that the ex_data is freed early (i.e.
71          * before OPENSSL_cleanup() is called), so if we get here we can safely
72          * ignore this operation. We just treat it as an error.
73          */
74          return NULL;
75     }
76
77     ip = &ex_data[class_index];
78     CRYPTO_THREAD_write_lock(ex_data_lock);
79     return ip;
80 }
81
82 static void cleanup_cb(EX_CALLBACK *funcs)
83 {
84     OPENSSL_free(funcs);
85 }
86
87 /*
88  * Release all "ex_data" state to prevent memory leaks. This can't be made
89  * thread-safe without overhauling a lot of stuff, and shouldn't really be
90  * called under potential race-conditions anyway (it's for program shutdown
91  * after all).
92  */
93 void crypto_cleanup_all_ex_data_int(void)
94 {
95     int i;
96
97     for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
98         EX_CALLBACKS *ip = &ex_data[i];
99
100         sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
101         ip->meth = NULL;
102     }
103
104     CRYPTO_THREAD_lock_free(ex_data_lock);
105     ex_data_lock = NULL;
106 }
107
108
109 /*
110  * Unregister a new index by replacing the callbacks with no-ops.
111  * Any in-use instances are leaked.
112  */
113 static void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
114                      long argl, void *argp)
115 {
116 }
117
118 static void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
119                        long argl, void *argp)
120 {
121 }
122
123 static int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
124                      void *from_d, int idx,
125                      long argl, void *argp)
126 {
127     return 1;
128 }
129
130 int CRYPTO_free_ex_index(int class_index, int idx)
131 {
132     EX_CALLBACKS *ip = get_and_lock(class_index);
133     EX_CALLBACK *a;
134     int toret = 0;
135
136     if (ip == NULL)
137         return 0;
138     if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
139         goto err;
140     a = sk_EX_CALLBACK_value(ip->meth, idx);
141     if (a == NULL)
142         goto err;
143     a->new_func = dummy_new;
144     a->dup_func = dummy_dup;
145     a->free_func = dummy_free;
146     toret = 1;
147 err:
148     CRYPTO_THREAD_unlock(ex_data_lock);
149     return toret;
150 }
151
152 /*
153  * Register a new index.
154  */
155 int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
156                             CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
157                             CRYPTO_EX_free *free_func)
158 {
159     int toret = -1;
160     EX_CALLBACK *a;
161     EX_CALLBACKS *ip = get_and_lock(class_index);
162
163     if (ip == NULL)
164         return -1;
165
166     if (ip->meth == NULL) {
167         ip->meth = sk_EX_CALLBACK_new_null();
168         /* We push an initial value on the stack because the SSL
169          * "app_data" routines use ex_data index zero.  See RT 3710. */
170         if (ip->meth == NULL
171             || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
172             CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
173             goto err;
174         }
175     }
176
177     a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
178     if (a == NULL) {
179         CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
180         goto err;
181     }
182     a->argl = argl;
183     a->argp = argp;
184     a->new_func = new_func;
185     a->dup_func = dup_func;
186     a->free_func = free_func;
187
188     if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
189         CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
190         OPENSSL_free(a);
191         goto err;
192     }
193     toret = sk_EX_CALLBACK_num(ip->meth) - 1;
194     (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
195
196  err:
197     CRYPTO_THREAD_unlock(ex_data_lock);
198     return toret;
199 }
200
201 /*
202  * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
203  * calling new() callbacks for each index in the class used by this variable
204  * Thread-safe by copying a class's array of "EX_CALLBACK" entries
205  * in the lock, then using them outside the lock. Note this only applies
206  * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
207  */
208 int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
209 {
210     int mx, i;
211     void *ptr;
212     EX_CALLBACK **storage = NULL;
213     EX_CALLBACK *stack[10];
214     EX_CALLBACKS *ip = get_and_lock(class_index);
215
216     if (ip == NULL)
217         return 0;
218
219     ad->sk = NULL;
220
221     mx = sk_EX_CALLBACK_num(ip->meth);
222     if (mx > 0) {
223         if (mx < (int)OSSL_NELEM(stack))
224             storage = stack;
225         else
226             storage = OPENSSL_malloc(sizeof(*storage) * mx);
227         if (storage != NULL)
228             for (i = 0; i < mx; i++)
229                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
230     }
231     CRYPTO_THREAD_unlock(ex_data_lock);
232
233     if (mx > 0 && storage == NULL) {
234         CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
235         return 0;
236     }
237     for (i = 0; i < mx; i++) {
238         if (storage[i] && storage[i]->new_func) {
239             ptr = CRYPTO_get_ex_data(ad, i);
240             storage[i]->new_func(obj, ptr, ad, i,
241                                  storage[i]->argl, storage[i]->argp);
242         }
243     }
244     if (storage != stack)
245         OPENSSL_free(storage);
246     return 1;
247 }
248
249 /*
250  * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
251  * for each index in the class used by this variable
252  */
253 int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
254                        const CRYPTO_EX_DATA *from)
255 {
256     int mx, j, i;
257     void *ptr;
258     EX_CALLBACK *stack[10];
259     EX_CALLBACK **storage = NULL;
260     EX_CALLBACKS *ip;
261     int toret = 0;
262
263     if (from->sk == NULL)
264         /* Nothing to copy over */
265         return 1;
266     if ((ip = get_and_lock(class_index)) == NULL)
267         return 0;
268
269     mx = sk_EX_CALLBACK_num(ip->meth);
270     j = sk_void_num(from->sk);
271     if (j < mx)
272         mx = j;
273     if (mx > 0) {
274         if (mx < (int)OSSL_NELEM(stack))
275             storage = stack;
276         else
277             storage = OPENSSL_malloc(sizeof(*storage) * mx);
278         if (storage != NULL)
279             for (i = 0; i < mx; i++)
280                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
281     }
282     CRYPTO_THREAD_unlock(ex_data_lock);
283
284     if (mx == 0)
285         return 1;
286     if (storage == NULL) {
287         CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
288         return 0;
289     }
290     if (!CRYPTO_set_ex_data(to, mx - 1, NULL))
291         goto err;
292
293     for (i = 0; i < mx; i++) {
294         ptr = CRYPTO_get_ex_data(from, i);
295         if (storage[i] && storage[i]->dup_func)
296             if (!storage[i]->dup_func(to, from, &ptr, i,
297                                       storage[i]->argl, storage[i]->argp))
298                 goto err;
299         CRYPTO_set_ex_data(to, i, ptr);
300     }
301     toret = 1;
302  err:
303     if (storage != stack)
304         OPENSSL_free(storage);
305     return toret;
306 }
307
308
309 /*
310  * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
311  * each index in the class used by this variable
312  */
313 void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
314 {
315     int mx, i;
316     EX_CALLBACKS *ip;
317     void *ptr;
318     EX_CALLBACK *f;
319     EX_CALLBACK *stack[10];
320     EX_CALLBACK **storage = NULL;
321
322     if ((ip = get_and_lock(class_index)) == NULL)
323         goto err;
324
325     mx = sk_EX_CALLBACK_num(ip->meth);
326     if (mx > 0) {
327         if (mx < (int)OSSL_NELEM(stack))
328             storage = stack;
329         else
330             storage = OPENSSL_malloc(sizeof(*storage) * mx);
331         if (storage != NULL)
332             for (i = 0; i < mx; i++)
333                 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
334     }
335     CRYPTO_THREAD_unlock(ex_data_lock);
336
337     for (i = 0; i < mx; i++) {
338         if (storage != NULL)
339             f = storage[i];
340         else {
341             CRYPTO_THREAD_write_lock(ex_data_lock);
342             f = sk_EX_CALLBACK_value(ip->meth, i);
343             CRYPTO_THREAD_unlock(ex_data_lock);
344         }
345         if (f != NULL && f->free_func != NULL) {
346             ptr = CRYPTO_get_ex_data(ad, i);
347             f->free_func(obj, ptr, ad, i, f->argl, f->argp);
348         }
349     }
350
351     if (storage != stack)
352         OPENSSL_free(storage);
353  err:
354     sk_void_free(ad->sk);
355     ad->sk = NULL;
356 }
357
358 /*
359  * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
360  * particular index in the class used by this variable
361  */
362 int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
363 {
364     int i;
365
366     if (ad->sk == NULL) {
367         if ((ad->sk = sk_void_new_null()) == NULL) {
368             CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
369             return 0;
370         }
371     }
372
373     for (i = sk_void_num(ad->sk); i <= idx; ++i) {
374         if (!sk_void_push(ad->sk, NULL)) {
375             CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
376             return 0;
377         }
378     }
379     sk_void_set(ad->sk, idx, val);
380     return 1;
381 }
382
383 /*
384  * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
385  * particular index in the class used by this variable
386  */
387 void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
388 {
389     if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
390         return NULL;
391     return sk_void_value(ad->sk, idx);
392 }