xref: /freebsd/crypto/openssl/crypto/dso/dso_lib.c (revision b077aed3)
16f9291ceSJung-uk Kim /*
2b077aed3SPierre Pronchery  * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
3ddd58736SKris Kennaway  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
8ddd58736SKris Kennaway  */
9ddd58736SKris Kennaway 
1017f01e99SJung-uk Kim #include "dso_local.h"
11e71b7053SJung-uk Kim #include "internal/refcount.h"
12ddd58736SKris Kennaway 
DSO_new_method(DSO_METHOD * meth)13e71b7053SJung-uk Kim static DSO *DSO_new_method(DSO_METHOD *meth)
14ddd58736SKris Kennaway {
15ddd58736SKris Kennaway     DSO *ret;
16ddd58736SKris Kennaway 
17e71b7053SJung-uk Kim     ret = OPENSSL_zalloc(sizeof(*ret));
186f9291ceSJung-uk Kim     if (ret == NULL) {
19b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
20e71b7053SJung-uk Kim         return NULL;
21ddd58736SKris Kennaway     }
221f13597dSJung-uk Kim     ret->meth_data = sk_void_new_null();
236f9291ceSJung-uk Kim     if (ret->meth_data == NULL) {
24ddd58736SKris Kennaway         /* sk_new doesn't generate any errors so we do */
25b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
26ddd58736SKris Kennaway         OPENSSL_free(ret);
27e71b7053SJung-uk Kim         return NULL;
28ddd58736SKris Kennaway     }
29b077aed3SPierre Pronchery     ret->meth = DSO_METHOD_openssl();
30ddd58736SKris Kennaway     ret->references = 1;
31e71b7053SJung-uk Kim     ret->lock = CRYPTO_THREAD_lock_new();
32e71b7053SJung-uk Kim     if (ret->lock == NULL) {
33b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
344c6a0400SJung-uk Kim         sk_void_free(ret->meth_data);
35ddd58736SKris Kennaway         OPENSSL_free(ret);
36e71b7053SJung-uk Kim         return NULL;
37e71b7053SJung-uk Kim     }
38e71b7053SJung-uk Kim 
39e71b7053SJung-uk Kim     if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
40e71b7053SJung-uk Kim         DSO_free(ret);
41ddd58736SKris Kennaway         ret = NULL;
42ddd58736SKris Kennaway     }
43e71b7053SJung-uk Kim 
44e71b7053SJung-uk Kim     return ret;
45e71b7053SJung-uk Kim }
46e71b7053SJung-uk Kim 
DSO_new(void)47e71b7053SJung-uk Kim DSO *DSO_new(void)
48e71b7053SJung-uk Kim {
49e71b7053SJung-uk Kim     return DSO_new_method(NULL);
50ddd58736SKris Kennaway }
51ddd58736SKris Kennaway 
DSO_free(DSO * dso)52ddd58736SKris Kennaway int DSO_free(DSO *dso)
53ddd58736SKris Kennaway {
54ddd58736SKris Kennaway     int i;
55ddd58736SKris Kennaway 
56e71b7053SJung-uk Kim     if (dso == NULL)
57e71b7053SJung-uk Kim         return 1;
58ddd58736SKris Kennaway 
59e71b7053SJung-uk Kim     if (CRYPTO_DOWN_REF(&dso->references, &i, dso->lock) <= 0)
60e71b7053SJung-uk Kim         return 0;
61e71b7053SJung-uk Kim 
62e71b7053SJung-uk Kim     REF_PRINT_COUNT("DSO", dso);
636f9291ceSJung-uk Kim     if (i > 0)
64e71b7053SJung-uk Kim         return 1;
65e71b7053SJung-uk Kim     REF_ASSERT_ISNT(i < 0);
66ddd58736SKris Kennaway 
67e71b7053SJung-uk Kim     if ((dso->flags & DSO_FLAG_NO_UNLOAD_ON_FREE) == 0) {
686f9291ceSJung-uk Kim         if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
69b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_DSO, DSO_R_UNLOAD_FAILED);
70e71b7053SJung-uk Kim             return 0;
71e71b7053SJung-uk Kim         }
72ddd58736SKris Kennaway     }
73ddd58736SKris Kennaway 
746f9291ceSJung-uk Kim     if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
75b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_FINISH_FAILED);
76e71b7053SJung-uk Kim         return 0;
77ddd58736SKris Kennaway     }
78ddd58736SKris Kennaway 
791f13597dSJung-uk Kim     sk_void_free(dso->meth_data);
805c87c606SMark Murray     OPENSSL_free(dso->filename);
815c87c606SMark Murray     OPENSSL_free(dso->loaded_filename);
82e71b7053SJung-uk Kim     CRYPTO_THREAD_lock_free(dso->lock);
83ddd58736SKris Kennaway     OPENSSL_free(dso);
84e71b7053SJung-uk Kim     return 1;
85ddd58736SKris Kennaway }
86ddd58736SKris Kennaway 
DSO_flags(DSO * dso)87ddd58736SKris Kennaway int DSO_flags(DSO *dso)
88ddd58736SKris Kennaway {
89ddd58736SKris Kennaway     return ((dso == NULL) ? 0 : dso->flags);
90ddd58736SKris Kennaway }
91ddd58736SKris Kennaway 
DSO_up_ref(DSO * dso)925c87c606SMark Murray int DSO_up_ref(DSO *dso)
93ddd58736SKris Kennaway {
94e71b7053SJung-uk Kim     int i;
95e71b7053SJung-uk Kim 
966f9291ceSJung-uk Kim     if (dso == NULL) {
97b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
98e71b7053SJung-uk Kim         return 0;
99ddd58736SKris Kennaway     }
100ddd58736SKris Kennaway 
101e71b7053SJung-uk Kim     if (CRYPTO_UP_REF(&dso->references, &i, dso->lock) <= 0)
102e71b7053SJung-uk Kim         return 0;
103e71b7053SJung-uk Kim 
104b077aed3SPierre Pronchery     REF_PRINT_COUNT("DSO", dso);
105e71b7053SJung-uk Kim     REF_ASSERT_ISNT(i < 2);
106e71b7053SJung-uk Kim     return ((i > 1) ? 1 : 0);
107ddd58736SKris Kennaway }
108ddd58736SKris Kennaway 
DSO_load(DSO * dso,const char * filename,DSO_METHOD * meth,int flags)109ddd58736SKris Kennaway DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags)
110ddd58736SKris Kennaway {
111ddd58736SKris Kennaway     DSO *ret;
112ddd58736SKris Kennaway     int allocated = 0;
113ddd58736SKris Kennaway 
1146f9291ceSJung-uk Kim     if (dso == NULL) {
115ddd58736SKris Kennaway         ret = DSO_new_method(meth);
1166f9291ceSJung-uk Kim         if (ret == NULL) {
117b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
1185c87c606SMark Murray             goto err;
119ddd58736SKris Kennaway         }
120ddd58736SKris Kennaway         allocated = 1;
1215c87c606SMark Murray         /* Pass the provided flags to the new DSO object */
1226f9291ceSJung-uk Kim         if (DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) {
123b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_DSO, DSO_R_CTRL_FAILED);
1245c87c606SMark Murray             goto err;
1255c87c606SMark Murray         }
1266f9291ceSJung-uk Kim     } else
1275c87c606SMark Murray         ret = dso;
1285c87c606SMark Murray     /* Don't load if we're currently already loaded */
1296f9291ceSJung-uk Kim     if (ret->filename != NULL) {
130b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED);
1315c87c606SMark Murray         goto err;
1325c87c606SMark Murray     }
1336f9291ceSJung-uk Kim     /*
1346f9291ceSJung-uk Kim      * filename can only be NULL if we were passed a dso that already has one
1356f9291ceSJung-uk Kim      * set.
1366f9291ceSJung-uk Kim      */
1375c87c606SMark Murray     if (filename != NULL)
1386f9291ceSJung-uk Kim         if (!DSO_set_filename(ret, filename)) {
139b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_DSO, DSO_R_SET_FILENAME_FAILED);
1405c87c606SMark Murray             goto err;
1415c87c606SMark Murray         }
1425c87c606SMark Murray     filename = ret->filename;
1436f9291ceSJung-uk Kim     if (filename == NULL) {
144b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME);
1455c87c606SMark Murray         goto err;
146ddd58736SKris Kennaway     }
1476f9291ceSJung-uk Kim     if (ret->meth->dso_load == NULL) {
148b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED);
1495c87c606SMark Murray         goto err;
150ddd58736SKris Kennaway     }
1516f9291ceSJung-uk Kim     if (!ret->meth->dso_load(ret)) {
152b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_LOAD_FAILED);
1535c87c606SMark Murray         goto err;
154ddd58736SKris Kennaway     }
155ddd58736SKris Kennaway     /* Load succeeded */
156e71b7053SJung-uk Kim     return ret;
1575c87c606SMark Murray  err:
1585c87c606SMark Murray     if (allocated)
1595c87c606SMark Murray         DSO_free(ret);
160e71b7053SJung-uk Kim     return NULL;
161ddd58736SKris Kennaway }
162ddd58736SKris Kennaway 
DSO_bind_func(DSO * dso,const char * symname)163ddd58736SKris Kennaway DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname)
164ddd58736SKris Kennaway {
165ddd58736SKris Kennaway     DSO_FUNC_TYPE ret = NULL;
166ddd58736SKris Kennaway 
1676f9291ceSJung-uk Kim     if ((dso == NULL) || (symname == NULL)) {
168b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
169e71b7053SJung-uk Kim         return NULL;
170ddd58736SKris Kennaway     }
1716f9291ceSJung-uk Kim     if (dso->meth->dso_bind_func == NULL) {
172b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED);
173e71b7053SJung-uk Kim         return NULL;
174ddd58736SKris Kennaway     }
1756f9291ceSJung-uk Kim     if ((ret = dso->meth->dso_bind_func(dso, symname)) == NULL) {
176b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_SYM_FAILURE);
177e71b7053SJung-uk Kim         return NULL;
178ddd58736SKris Kennaway     }
179ddd58736SKris Kennaway     /* Success */
180e71b7053SJung-uk Kim     return ret;
181ddd58736SKris Kennaway }
182ddd58736SKris Kennaway 
1836f9291ceSJung-uk Kim /*
1846f9291ceSJung-uk Kim  * I don't really like these *_ctrl functions very much to be perfectly
1856f9291ceSJung-uk Kim  * honest. For one thing, I think I have to return a negative value for any
1866f9291ceSJung-uk Kim  * error because possible DSO_ctrl() commands may return values such as
1876f9291ceSJung-uk Kim  * "size"s that can legitimately be zero (making the standard
1886f9291ceSJung-uk Kim  * "if (DSO_cmd(...))" form that works almost everywhere else fail at odd
1896f9291ceSJung-uk Kim  * times. I'd prefer "output" values to be passed by reference and the return
1906f9291ceSJung-uk Kim  * value as success/failure like usual ... but we conform when we must... :-)
1916f9291ceSJung-uk Kim  */
DSO_ctrl(DSO * dso,int cmd,long larg,void * parg)192ddd58736SKris Kennaway long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg)
193ddd58736SKris Kennaway {
1946f9291ceSJung-uk Kim     if (dso == NULL) {
195b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
196e71b7053SJung-uk Kim         return -1;
197ddd58736SKris Kennaway     }
1986f9291ceSJung-uk Kim     /*
1996f9291ceSJung-uk Kim      * We should intercept certain generic commands and only pass control to
2006f9291ceSJung-uk Kim      * the method-specific ctrl() function if it's something we don't handle.
2016f9291ceSJung-uk Kim      */
2026f9291ceSJung-uk Kim     switch (cmd) {
2035c87c606SMark Murray     case DSO_CTRL_GET_FLAGS:
2045c87c606SMark Murray         return dso->flags;
2055c87c606SMark Murray     case DSO_CTRL_SET_FLAGS:
2065c87c606SMark Murray         dso->flags = (int)larg;
207e71b7053SJung-uk Kim         return 0;
2085c87c606SMark Murray     case DSO_CTRL_OR_FLAGS:
2095c87c606SMark Murray         dso->flags |= (int)larg;
210e71b7053SJung-uk Kim         return 0;
2115c87c606SMark Murray     default:
2125c87c606SMark Murray         break;
2135c87c606SMark Murray     }
2146f9291ceSJung-uk Kim     if ((dso->meth == NULL) || (dso->meth->dso_ctrl == NULL)) {
215b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED);
216e71b7053SJung-uk Kim         return -1;
217ddd58736SKris Kennaway     }
218e71b7053SJung-uk Kim     return dso->meth->dso_ctrl(dso, cmd, larg, parg);
2195c87c606SMark Murray }
2205c87c606SMark Murray 
DSO_get_filename(DSO * dso)2215c87c606SMark Murray const char *DSO_get_filename(DSO *dso)
2225c87c606SMark Murray {
2236f9291ceSJung-uk Kim     if (dso == NULL) {
224b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
225e71b7053SJung-uk Kim         return NULL;
2265c87c606SMark Murray     }
227e71b7053SJung-uk Kim     return dso->filename;
2285c87c606SMark Murray }
2295c87c606SMark Murray 
DSO_set_filename(DSO * dso,const char * filename)2305c87c606SMark Murray int DSO_set_filename(DSO *dso, const char *filename)
2315c87c606SMark Murray {
2325c87c606SMark Murray     char *copied;
2335c87c606SMark Murray 
2346f9291ceSJung-uk Kim     if ((dso == NULL) || (filename == NULL)) {
235b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
236e71b7053SJung-uk Kim         return 0;
2375c87c606SMark Murray     }
2386f9291ceSJung-uk Kim     if (dso->loaded_filename) {
239b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_DSO_ALREADY_LOADED);
240e71b7053SJung-uk Kim         return 0;
2415c87c606SMark Murray     }
2425c87c606SMark Murray     /* We'll duplicate filename */
243e71b7053SJung-uk Kim     copied = OPENSSL_strdup(filename);
2446f9291ceSJung-uk Kim     if (copied == NULL) {
245b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
246e71b7053SJung-uk Kim         return 0;
2475c87c606SMark Murray     }
2485c87c606SMark Murray     OPENSSL_free(dso->filename);
2495c87c606SMark Murray     dso->filename = copied;
250e71b7053SJung-uk Kim     return 1;
2515c87c606SMark Murray }
2525c87c606SMark Murray 
DSO_merge(DSO * dso,const char * filespec1,const char * filespec2)2533b4e3dcbSSimon L. B. Nielsen char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2)
2543b4e3dcbSSimon L. B. Nielsen {
2553b4e3dcbSSimon L. B. Nielsen     char *result = NULL;
2563b4e3dcbSSimon L. B. Nielsen 
2576f9291ceSJung-uk Kim     if (dso == NULL || filespec1 == NULL) {
258b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
259e71b7053SJung-uk Kim         return NULL;
2603b4e3dcbSSimon L. B. Nielsen     }
2616f9291ceSJung-uk Kim     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
2623b4e3dcbSSimon L. B. Nielsen         if (dso->merger != NULL)
2633b4e3dcbSSimon L. B. Nielsen             result = dso->merger(dso, filespec1, filespec2);
2643b4e3dcbSSimon L. B. Nielsen         else if (dso->meth->dso_merger != NULL)
2656f9291ceSJung-uk Kim             result = dso->meth->dso_merger(dso, filespec1, filespec2);
2663b4e3dcbSSimon L. B. Nielsen     }
267e71b7053SJung-uk Kim     return result;
2683b4e3dcbSSimon L. B. Nielsen }
2693b4e3dcbSSimon L. B. Nielsen 
DSO_convert_filename(DSO * dso,const char * filename)2705c87c606SMark Murray char *DSO_convert_filename(DSO *dso, const char *filename)
2715c87c606SMark Murray {
2725c87c606SMark Murray     char *result = NULL;
2735c87c606SMark Murray 
2746f9291ceSJung-uk Kim     if (dso == NULL) {
275b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
276e71b7053SJung-uk Kim         return NULL;
2775c87c606SMark Murray     }
2785c87c606SMark Murray     if (filename == NULL)
2795c87c606SMark Murray         filename = dso->filename;
2806f9291ceSJung-uk Kim     if (filename == NULL) {
281b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME);
282e71b7053SJung-uk Kim         return NULL;
2835c87c606SMark Murray     }
2846f9291ceSJung-uk Kim     if ((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) {
2855c87c606SMark Murray         if (dso->name_converter != NULL)
2865c87c606SMark Murray             result = dso->name_converter(dso, filename);
2875c87c606SMark Murray         else if (dso->meth->dso_name_converter != NULL)
2885c87c606SMark Murray             result = dso->meth->dso_name_converter(dso, filename);
2895c87c606SMark Murray     }
2906f9291ceSJung-uk Kim     if (result == NULL) {
291e71b7053SJung-uk Kim         result = OPENSSL_strdup(filename);
2926f9291ceSJung-uk Kim         if (result == NULL) {
293b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
294e71b7053SJung-uk Kim             return NULL;
2955c87c606SMark Murray         }
2965c87c606SMark Murray     }
297e71b7053SJung-uk Kim     return result;
2985c87c606SMark Murray }
2991f13597dSJung-uk Kim 
DSO_pathbyaddr(void * addr,char * path,int sz)3001f13597dSJung-uk Kim int DSO_pathbyaddr(void *addr, char *path, int sz)
3011f13597dSJung-uk Kim {
302b077aed3SPierre Pronchery     DSO_METHOD *meth = DSO_METHOD_openssl();
303b077aed3SPierre Pronchery 
3046f9291ceSJung-uk Kim     if (meth->pathbyaddr == NULL) {
305b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED);
3061f13597dSJung-uk Kim         return -1;
3071f13597dSJung-uk Kim     }
3081f13597dSJung-uk Kim     return (*meth->pathbyaddr) (addr, path, sz);
3091f13597dSJung-uk Kim }
3101f13597dSJung-uk Kim 
DSO_dsobyaddr(void * addr,int flags)311e71b7053SJung-uk Kim DSO *DSO_dsobyaddr(void *addr, int flags)
312e71b7053SJung-uk Kim {
313e71b7053SJung-uk Kim     DSO *ret = NULL;
314e71b7053SJung-uk Kim     char *filename = NULL;
315e71b7053SJung-uk Kim     int len = DSO_pathbyaddr(addr, NULL, 0);
316e71b7053SJung-uk Kim 
317e71b7053SJung-uk Kim     if (len < 0)
318e71b7053SJung-uk Kim         return NULL;
319e71b7053SJung-uk Kim 
320e71b7053SJung-uk Kim     filename = OPENSSL_malloc(len);
321e71b7053SJung-uk Kim     if (filename != NULL
322e71b7053SJung-uk Kim             && DSO_pathbyaddr(addr, filename, len) == len)
323e71b7053SJung-uk Kim         ret = DSO_load(NULL, filename, NULL, flags);
324e71b7053SJung-uk Kim 
325e71b7053SJung-uk Kim     OPENSSL_free(filename);
326e71b7053SJung-uk Kim     return ret;
327e71b7053SJung-uk Kim }
328e71b7053SJung-uk Kim 
DSO_global_lookup(const char * name)3291f13597dSJung-uk Kim void *DSO_global_lookup(const char *name)
3301f13597dSJung-uk Kim {
331b077aed3SPierre Pronchery     DSO_METHOD *meth = DSO_METHOD_openssl();
332b077aed3SPierre Pronchery 
3336f9291ceSJung-uk Kim     if (meth->globallookup == NULL) {
334b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DSO, DSO_R_UNSUPPORTED);
3351f13597dSJung-uk Kim         return NULL;
3361f13597dSJung-uk Kim     }
3371f13597dSJung-uk Kim     return (*meth->globallookup) (name);
3381f13597dSJung-uk Kim }
339