2 * Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include "dso_local.h"
16 /* Part of the hack in "dl_load" ... */
17 # define DSO_MAX_TRANSLATED_SIZE 256
19 static int dl_load(DSO
*dso
);
20 static int dl_unload(DSO
*dso
);
21 static DSO_FUNC_TYPE
dl_bind_func(DSO
*dso
, const char *symname
);
22 static char *dl_name_converter(DSO
*dso
, const char *filename
);
23 static char *dl_merger(DSO
*dso
, const char *filespec1
,
24 const char *filespec2
);
25 static int dl_pathbyaddr(void *addr
, char *path
, int sz
);
26 static void *dl_globallookup(const char *name
);
28 static DSO_METHOD dso_meth_dl
= {
29 "OpenSSL 'dl' shared library method",
42 DSO_METHOD
*DSO_METHOD_openssl(void)
48 * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
49 * (shl_t) returned from shl_load(). NB: I checked on HPUX11 and shl_t is
50 * itself a pointer type so the cast is safe.
53 static int dl_load(DSO
*dso
)
57 * We don't do any fancy retries or anything, just take the method's (or
58 * DSO's if it has the callback set) best translation of the
59 * platform-independent filename and try once with that.
61 char *filename
= DSO_convert_filename(dso
, NULL
);
63 if (filename
== NULL
) {
64 ERR_raise(ERR_LIB_DSO
, DSO_R_NO_FILENAME
);
67 ptr
= shl_load(filename
, BIND_IMMEDIATE
|
68 (dso
->flags
& DSO_FLAG_NO_NAME_TRANSLATION
? 0 :
73 if (openssl_strerror_r(errno
, errbuf
, sizeof(errbuf
)))
74 ERR_raise_data(ERR_LIB_DSO
, DSO_R_LOAD_FAILED
,
75 "filename(%s): %s", filename
, errbuf
);
77 ERR_raise_data(ERR_LIB_DSO
, DSO_R_LOAD_FAILED
,
78 "filename(%s): errno %d", filename
, errno
);
81 if (!sk_push(dso
->meth_data
, (char *)ptr
)) {
82 ERR_raise(ERR_LIB_DSO
, DSO_R_STACK_ERROR
);
86 * Success, stick the converted filename we've loaded under into the DSO
87 * (it also serves as the indicator that we are currently loaded).
89 dso
->loaded_filename
= filename
;
93 OPENSSL_free(filename
);
99 static int dl_unload(DSO
*dso
)
103 ERR_raise(ERR_LIB_DSO
, ERR_R_PASSED_NULL_PARAMETER
);
106 if (sk_num(dso
->meth_data
) < 1)
108 /* Is this statement legal? */
109 ptr
= (shl_t
) sk_pop(dso
->meth_data
);
111 ERR_raise(ERR_LIB_DSO
, DSO_R_NULL_HANDLE
);
113 * Should push the value back onto the stack in case of a retry.
115 sk_push(dso
->meth_data
, (char *)ptr
);
122 static DSO_FUNC_TYPE
dl_bind_func(DSO
*dso
, const char *symname
)
127 if ((dso
== NULL
) || (symname
== NULL
)) {
128 ERR_raise(ERR_LIB_DSO
, ERR_R_PASSED_NULL_PARAMETER
);
131 if (sk_num(dso
->meth_data
) < 1) {
132 ERR_raise(ERR_LIB_DSO
, DSO_R_STACK_ERROR
);
135 ptr
= (shl_t
) sk_value(dso
->meth_data
, sk_num(dso
->meth_data
) - 1);
137 ERR_raise(ERR_LIB_DSO
, DSO_R_NULL_HANDLE
);
140 if (shl_findsym(&ptr
, symname
, TYPE_UNDEFINED
, &sym
) < 0) {
143 if (openssl_strerror_r(errno
, errbuf
, sizeof(errbuf
)))
144 ERR_raise_data(ERR_LIB_DSO
, DSO_R_SYM_FAILURE
,
145 "symname(%s): %s", symname
, errbuf
);
147 ERR_raise_data(ERR_LIB_DSO
, DSO_R_SYM_FAILURE
,
148 "symname(%s): errno %d", symname
, errno
);
151 return (DSO_FUNC_TYPE
)sym
;
154 static char *dl_merger(DSO
*dso
, const char *filespec1
, const char *filespec2
)
158 if (!filespec1
&& !filespec2
) {
159 ERR_raise(ERR_LIB_DSO
, ERR_R_PASSED_NULL_PARAMETER
);
163 * If the first file specification is a rooted path, it rules. same goes
164 * if the second file specification is missing.
166 if (!filespec2
|| filespec1
[0] == '/') {
167 merged
= OPENSSL_strdup(filespec1
);
172 * If the first file specification is missing, the second one rules.
174 else if (!filespec1
) {
175 merged
= OPENSSL_strdup(filespec2
);
180 * This part isn't as trivial as it looks. It assumes that the
181 * second file specification really is a directory, and makes no
182 * checks whatsoever. Therefore, the result becomes the
183 * concatenation of filespec2 followed by a slash followed by
189 spec2len
= (filespec2
? strlen(filespec2
) : 0);
190 len
= spec2len
+ (filespec1
? strlen(filespec1
) : 0);
192 if (spec2len
&& filespec2
[spec2len
- 1] == '/') {
196 merged
= OPENSSL_malloc(len
+ 2);
199 strcpy(merged
, filespec2
);
200 merged
[spec2len
] = '/';
201 strcpy(&merged
[spec2len
+ 1], filespec1
);
207 * This function is identical to the one in dso_dlfcn.c, but as it is highly
208 * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at
209 * the same time, there's no great duplicating the code. Figuring out an
210 * elegant way to share one copy of the code would be more difficult and
211 * would not leave the implementations independent.
213 static char *dl_name_converter(DSO
*dso
, const char *filename
)
216 int len
, rsize
, transform
;
218 len
= strlen(filename
);
220 transform
= (strchr(filename
, '/') == NULL
);
222 /* We will convert this to "%s.s?" or "lib%s.s?" */
223 rsize
+= strlen(DSO_EXTENSION
); /* The length of ".s?" */
224 if ((DSO_flags(dso
) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY
) == 0)
225 rsize
+= 3; /* The length of "lib" */
227 translated
= OPENSSL_malloc(rsize
);
228 if (translated
== NULL
) {
229 ERR_raise(ERR_LIB_DSO
, DSO_R_NAME_TRANSLATION_FAILED
);
233 if ((DSO_flags(dso
) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY
) == 0)
234 sprintf(translated
, "lib%s%s", filename
, DSO_EXTENSION
);
236 sprintf(translated
, "%s%s", filename
, DSO_EXTENSION
);
238 sprintf(translated
, "%s", filename
);
242 static int dl_pathbyaddr(void *addr
, char *path
, int sz
)
244 struct shl_descriptor inf
;
249 int (*f
) (void *, char *, int);
257 for (i
= -1; shl_get_r(i
, &inf
) == 0; i
++) {
258 if (((size_t)addr
>= inf
.tstart
&& (size_t)addr
< inf
.tend
) ||
259 ((size_t)addr
>= inf
.dstart
&& (size_t)addr
< inf
.dend
)) {
260 len
= (int)strlen(inf
.filename
);
265 memcpy(path
, inf
.filename
, len
);
274 static void *dl_globallookup(const char *name
)
279 return shl_findsym(&h
, name
, TYPE_UNDEFINED
, &ret
) ? NULL
: ret
;