/src/openssl30/crypto/dso/dso_lib.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2000-2021 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 "dso_local.h" |
11 | | #include "internal/refcount.h" |
12 | | |
13 | | static DSO *DSO_new_method(DSO_METHOD *meth) |
14 | 0 | { |
15 | 0 | DSO *ret; |
16 | |
|
17 | 0 | ret = OPENSSL_zalloc(sizeof(*ret)); |
18 | 0 | if (ret == NULL) { |
19 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); |
20 | 0 | return NULL; |
21 | 0 | } |
22 | 0 | ret->meth_data = sk_void_new_null(); |
23 | 0 | if (ret->meth_data == NULL) { |
24 | | /* sk_new doesn't generate any errors so we do */ |
25 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); |
26 | 0 | OPENSSL_free(ret); |
27 | 0 | return NULL; |
28 | 0 | } |
29 | 0 | ret->meth = DSO_METHOD_openssl(); |
30 | 0 | ret->references = 1; |
31 | 0 | ret->lock = CRYPTO_THREAD_lock_new(); |
32 | 0 | if (ret->lock == NULL) { |
33 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); |
34 | 0 | sk_void_free(ret->meth_data); |
35 | 0 | OPENSSL_free(ret); |
36 | 0 | return NULL; |
37 | 0 | } |
38 | | |
39 | 0 | if ((ret->meth->init != NULL) && !ret->meth->init(ret)) { |
40 | 0 | DSO_free(ret); |
41 | 0 | ret = NULL; |
42 | 0 | } |
43 | |
|
44 | 0 | return ret; |
45 | 0 | } |
46 | | |
47 | | DSO *DSO_new(void) |
48 | 0 | { |
49 | 0 | return DSO_new_method(NULL); |
50 | 0 | } |
51 | | |
52 | | int DSO_free(DSO *dso) |
53 | 43 | { |
54 | 43 | int i; |
55 | | |
56 | 43 | if (dso == NULL) |
57 | 43 | return 1; |
58 | | |
59 | 0 | if (CRYPTO_DOWN_REF(&dso->references, &i, dso->lock) <= 0) |
60 | 0 | return 0; |
61 | | |
62 | 0 | REF_PRINT_COUNT("DSO", dso); |
63 | 0 | if (i > 0) |
64 | 0 | return 1; |
65 | 0 | REF_ASSERT_ISNT(i < 0); |
66 | |
|
67 | 0 | if ((dso->flags & DSO_FLAG_NO_UNLOAD_ON_FREE) == 0) { |
68 | 0 | if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) { |
69 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNLOAD_FAILED); |
70 | 0 | return 0; |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | 0 | if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) { |
75 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_FINISH_FAILED); |
76 | 0 | return 0; |
77 | 0 | } |
78 | | |
79 | 0 | sk_void_free(dso->meth_data); |
80 | 0 | OPENSSL_free(dso->filename); |
81 | 0 | OPENSSL_free(dso->loaded_filename); |
82 | 0 | CRYPTO_THREAD_lock_free(dso->lock); |
83 | 0 | OPENSSL_free(dso); |
84 | 0 | return 1; |
85 | 0 | } |
86 | | |
87 | | int DSO_flags(DSO *dso) |
88 | 0 | { |
89 | 0 | return ((dso == NULL) ? 0 : dso->flags); |
90 | 0 | } |
91 | | |
92 | | int DSO_up_ref(DSO *dso) |
93 | 0 | { |
94 | 0 | int i; |
95 | |
|
96 | 0 | if (dso == NULL) { |
97 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
98 | 0 | return 0; |
99 | 0 | } |
100 | | |
101 | 0 | if (CRYPTO_UP_REF(&dso->references, &i, dso->lock) <= 0) |
102 | 0 | return 0; |
103 | | |
104 | 0 | REF_PRINT_COUNT("DSO", dso); |
105 | 0 | REF_ASSERT_ISNT(i < 2); |
106 | 0 | return ((i > 1) ? 1 : 0); |
107 | 0 | } |
108 | | |
109 | | DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags) |
110 | 0 | { |
111 | 0 | DSO *ret; |
112 | 0 | int allocated = 0; |
113 | |
|
114 | 0 | if (dso == NULL) { |
115 | 0 | ret = DSO_new_method(meth); |
116 | 0 | if (ret == NULL) { |
117 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); |
118 | 0 | goto err; |
119 | 0 | } |
120 | 0 | allocated = 1; |
121 | | /* Pass the provided flags to the new DSO object */ |
122 | 0 | if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) { |
123 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_CTRL_FAILED); |
124 | 0 | goto err; |
125 | 0 | } |
126 | 0 | } else |
127 | 0 | ret = dso; |
128 | | /* Don't load if we're currently already loaded */ |
129 | 0 | if (ret->filename != NULL) { |
130 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED); |
131 | 0 | goto err; |
132 | 0 | } |
133 | | /* |
134 | | * filename can only be NULL if we were passed a dso that already has one |
135 | | * set. |
136 | | */ |
137 | 0 | if (filename != NULL) |
138 | 0 | if (!DSO_set_filename(ret, filename)) { |
139 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_SET_FILENAME_FAILED); |
140 | 0 | goto err; |
141 | 0 | } |
142 | 0 | filename = ret->filename; |
143 | 0 | if (filename == NULL) { |
144 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME); |
145 | 0 | goto err; |
146 | 0 | } |
147 | 0 | if (ret->meth->dso_load == NULL) { |
148 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
149 | 0 | goto err; |
150 | 0 | } |
151 | 0 | if (!ret->meth->dso_load(ret)) { |
152 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_LOAD_FAILED); |
153 | 0 | goto err; |
154 | 0 | } |
155 | | /* Load succeeded */ |
156 | 0 | return ret; |
157 | 0 | err: |
158 | 0 | if (allocated) |
159 | 0 | DSO_free(ret); |
160 | 0 | return NULL; |
161 | 0 | } |
162 | | |
163 | | DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname) |
164 | 0 | { |
165 | 0 | DSO_FUNC_TYPE ret = NULL; |
166 | |
|
167 | 0 | if ((dso == NULL) || (symname == NULL)) { |
168 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
169 | 0 | return NULL; |
170 | 0 | } |
171 | 0 | if (dso->meth->dso_bind_func == NULL) { |
172 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
173 | 0 | return NULL; |
174 | 0 | } |
175 | 0 | if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) { |
176 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_SYM_FAILURE); |
177 | 0 | return NULL; |
178 | 0 | } |
179 | | /* Success */ |
180 | 0 | return ret; |
181 | 0 | } |
182 | | |
183 | | /* |
184 | | * I don't really like these *_ctrl functions very much to be perfectly |
185 | | * honest. For one thing, I think I have to return a negative value for any |
186 | | * error because possible DSO_ctrl() commands may return values such as |
187 | | * "size"s that can legitimately be zero (making the standard |
188 | | * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd |
189 | | * times. I'd prefer "output" values to be passed by reference and the return |
190 | | * value as success/failure like usual ... but we conform when we must... :-) |
191 | | */ |
192 | | long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg) |
193 | 0 | { |
194 | 0 | if (dso == NULL) { |
195 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
196 | 0 | return -1; |
197 | 0 | } |
198 | | /* |
199 | | * We should intercept certain generic commands and only pass control to |
200 | | * the method-specific ctrl() function if it's something we don't handle. |
201 | | */ |
202 | 0 | switch (cmd) { |
203 | 0 | case DSO_CTRL_GET_FLAGS: |
204 | 0 | return dso->flags; |
205 | 0 | case DSO_CTRL_SET_FLAGS: |
206 | 0 | dso->flags = (int)larg; |
207 | 0 | return 0; |
208 | 0 | case DSO_CTRL_OR_FLAGS: |
209 | 0 | dso->flags |= (int)larg; |
210 | 0 | return 0; |
211 | 0 | default: |
212 | 0 | break; |
213 | 0 | } |
214 | 0 | if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) { |
215 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
216 | 0 | return -1; |
217 | 0 | } |
218 | 0 | return dso->meth->dso_ctrl(dso, cmd, larg, parg); |
219 | 0 | } |
220 | | |
221 | | const char *DSO_get_filename(DSO *dso) |
222 | 0 | { |
223 | 0 | if (dso == NULL) { |
224 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
225 | 0 | return NULL; |
226 | 0 | } |
227 | 0 | return dso->filename; |
228 | 0 | } |
229 | | |
230 | | int DSO_set_filename(DSO *dso, const char *filename) |
231 | 0 | { |
232 | 0 | char *copied; |
233 | |
|
234 | 0 | if ((dso == NULL) || (filename == NULL)) { |
235 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
236 | 0 | return 0; |
237 | 0 | } |
238 | 0 | if (dso->loaded_filename) { |
239 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED); |
240 | 0 | return 0; |
241 | 0 | } |
242 | | /* We'll duplicate filename */ |
243 | 0 | copied = OPENSSL_strdup(filename); |
244 | 0 | if (copied == NULL) { |
245 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); |
246 | 0 | return 0; |
247 | 0 | } |
248 | 0 | OPENSSL_free(dso->filename); |
249 | 0 | dso->filename = copied; |
250 | 0 | return 1; |
251 | 0 | } |
252 | | |
253 | | char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2) |
254 | 0 | { |
255 | 0 | char *result = NULL; |
256 | |
|
257 | 0 | if (dso == NULL || filespec1 == NULL) { |
258 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
259 | 0 | return NULL; |
260 | 0 | } |
261 | 0 | if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) { |
262 | 0 | if (dso->merger != NULL) |
263 | 0 | result = dso->merger(dso, filespec1, filespec2); |
264 | 0 | else if (dso->meth->dso_merger != NULL) |
265 | 0 | result = dso->meth->dso_merger(dso, filespec1, filespec2); |
266 | 0 | } |
267 | 0 | return result; |
268 | 0 | } |
269 | | |
270 | | char *DSO_convert_filename(DSO *dso, const char *filename) |
271 | 0 | { |
272 | 0 | char *result = NULL; |
273 | |
|
274 | 0 | if (dso == NULL) { |
275 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); |
276 | 0 | return NULL; |
277 | 0 | } |
278 | 0 | if (filename == NULL) |
279 | 0 | filename = dso->filename; |
280 | 0 | if (filename == NULL) { |
281 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME); |
282 | 0 | return NULL; |
283 | 0 | } |
284 | 0 | if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) { |
285 | 0 | if (dso->name_converter != NULL) |
286 | 0 | result = dso->name_converter(dso, filename); |
287 | 0 | else if (dso->meth->dso_name_converter != NULL) |
288 | 0 | result = dso->meth->dso_name_converter(dso, filename); |
289 | 0 | } |
290 | 0 | if (result == NULL) { |
291 | 0 | result = OPENSSL_strdup(filename); |
292 | 0 | if (result == NULL) { |
293 | 0 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); |
294 | 0 | return NULL; |
295 | 0 | } |
296 | 0 | } |
297 | 0 | return result; |
298 | 0 | } |
299 | | |
300 | | int DSO_pathbyaddr(void *addr, char *path, int sz) |
301 | 0 | { |
302 | 0 | DSO_METHOD *meth = DSO_METHOD_openssl(); |
303 | |
|
304 | 0 | if (meth->pathbyaddr == NULL) { |
305 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
306 | 0 | return -1; |
307 | 0 | } |
308 | 0 | return (*meth->pathbyaddr) (addr, path, sz); |
309 | 0 | } |
310 | | |
311 | | DSO *DSO_dsobyaddr(void *addr, int flags) |
312 | 0 | { |
313 | 0 | DSO *ret = NULL; |
314 | 0 | char *filename = NULL; |
315 | 0 | int len = DSO_pathbyaddr(addr, NULL, 0); |
316 | |
|
317 | 0 | if (len < 0) |
318 | 0 | return NULL; |
319 | | |
320 | 0 | filename = OPENSSL_malloc(len); |
321 | 0 | if (filename != NULL |
322 | 0 | && DSO_pathbyaddr(addr, filename, len) == len) |
323 | 0 | ret = DSO_load(NULL, filename, NULL, flags); |
324 | |
|
325 | 0 | OPENSSL_free(filename); |
326 | 0 | return ret; |
327 | 0 | } |
328 | | |
329 | | void *DSO_global_lookup(const char *name) |
330 | 0 | { |
331 | 0 | DSO_METHOD *meth = DSO_METHOD_openssl(); |
332 | |
|
333 | 0 | if (meth->globallookup == NULL) { |
334 | 0 | ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED); |
335 | 0 | return NULL; |
336 | 0 | } |
337 | 0 | return (*meth->globallookup) (name); |
338 | 0 | } |