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