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 |
|
---|
12 | #ifdef DSO_DL
|
---|
13 |
|
---|
14 | # include <dl.h>
|
---|
15 |
|
---|
16 | /* Part of the hack in "dl_load" ... */
|
---|
17 | # define DSO_MAX_TRANSLATED_SIZE 256
|
---|
18 |
|
---|
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);
|
---|
27 |
|
---|
28 | static DSO_METHOD dso_meth_dl = {
|
---|
29 | "OpenSSL 'dl' shared library method",
|
---|
30 | dl_load,
|
---|
31 | dl_unload,
|
---|
32 | dl_bind_func,
|
---|
33 | NULL, /* ctrl */
|
---|
34 | dl_name_converter,
|
---|
35 | dl_merger,
|
---|
36 | NULL, /* init */
|
---|
37 | NULL, /* finish */
|
---|
38 | dl_pathbyaddr,
|
---|
39 | dl_globallookup
|
---|
40 | };
|
---|
41 |
|
---|
42 | DSO_METHOD *DSO_METHOD_openssl(void)
|
---|
43 | {
|
---|
44 | return &dso_meth_dl;
|
---|
45 | }
|
---|
46 |
|
---|
47 | /*
|
---|
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.
|
---|
51 | */
|
---|
52 |
|
---|
53 | static int dl_load(DSO *dso)
|
---|
54 | {
|
---|
55 | shl_t ptr = NULL;
|
---|
56 | /*
|
---|
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.
|
---|
60 | */
|
---|
61 | char *filename = DSO_convert_filename(dso, NULL);
|
---|
62 |
|
---|
63 | if (filename == NULL) {
|
---|
64 | ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME);
|
---|
65 | goto err;
|
---|
66 | }
|
---|
67 | ptr = shl_load(filename, BIND_IMMEDIATE |
|
---|
68 | (dso->flags & DSO_FLAG_NO_NAME_TRANSLATION ? 0 :
|
---|
69 | DYNAMIC_PATH), 0L);
|
---|
70 | if (ptr == NULL) {
|
---|
71 | char errbuf[160];
|
---|
72 |
|
---|
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);
|
---|
76 | else
|
---|
77 | ERR_raise_data(ERR_LIB_DSO, DSO_R_LOAD_FAILED,
|
---|
78 | "filename(%s): errno %d", filename, errno);
|
---|
79 | goto err;
|
---|
80 | }
|
---|
81 | if (!sk_push(dso->meth_data, (char *)ptr)) {
|
---|
82 | ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR);
|
---|
83 | goto err;
|
---|
84 | }
|
---|
85 | /*
|
---|
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).
|
---|
88 | */
|
---|
89 | dso->loaded_filename = filename;
|
---|
90 | return 1;
|
---|
91 | err:
|
---|
92 | /* Cleanup! */
|
---|
93 | OPENSSL_free(filename);
|
---|
94 | if (ptr != NULL)
|
---|
95 | shl_unload(ptr);
|
---|
96 | return 0;
|
---|
97 | }
|
---|
98 |
|
---|
99 | static int dl_unload(DSO *dso)
|
---|
100 | {
|
---|
101 | shl_t ptr;
|
---|
102 | if (dso == NULL) {
|
---|
103 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
|
---|
104 | return 0;
|
---|
105 | }
|
---|
106 | if (sk_num(dso->meth_data) < 1)
|
---|
107 | return 1;
|
---|
108 | /* Is this statement legal? */
|
---|
109 | ptr = (shl_t) sk_pop(dso->meth_data);
|
---|
110 | if (ptr == NULL) {
|
---|
111 | ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE);
|
---|
112 | /*
|
---|
113 | * Should push the value back onto the stack in case of a retry.
|
---|
114 | */
|
---|
115 | sk_push(dso->meth_data, (char *)ptr);
|
---|
116 | return 0;
|
---|
117 | }
|
---|
118 | shl_unload(ptr);
|
---|
119 | return 1;
|
---|
120 | }
|
---|
121 |
|
---|
122 | static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname)
|
---|
123 | {
|
---|
124 | shl_t ptr;
|
---|
125 | void *sym;
|
---|
126 |
|
---|
127 | if ((dso == NULL) || (symname == NULL)) {
|
---|
128 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
|
---|
129 | return NULL;
|
---|
130 | }
|
---|
131 | if (sk_num(dso->meth_data) < 1) {
|
---|
132 | ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR);
|
---|
133 | return NULL;
|
---|
134 | }
|
---|
135 | ptr = (shl_t) sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
|
---|
136 | if (ptr == NULL) {
|
---|
137 | ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE);
|
---|
138 | return NULL;
|
---|
139 | }
|
---|
140 | if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0) {
|
---|
141 | char errbuf[160];
|
---|
142 |
|
---|
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);
|
---|
146 | else
|
---|
147 | ERR_raise_data(ERR_LIB_DSO, DSO_R_SYM_FAILURE,
|
---|
148 | "symname(%s): errno %d", symname, errno);
|
---|
149 | return NULL;
|
---|
150 | }
|
---|
151 | return (DSO_FUNC_TYPE)sym;
|
---|
152 | }
|
---|
153 |
|
---|
154 | static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2)
|
---|
155 | {
|
---|
156 | char *merged;
|
---|
157 |
|
---|
158 | if (!filespec1 && !filespec2) {
|
---|
159 | ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
|
---|
160 | return NULL;
|
---|
161 | }
|
---|
162 | /*
|
---|
163 | * If the first file specification is a rooted path, it rules. same goes
|
---|
164 | * if the second file specification is missing.
|
---|
165 | */
|
---|
166 | if (!filespec2 || filespec1[0] == '/') {
|
---|
167 | merged = OPENSSL_strdup(filespec1);
|
---|
168 | if (merged == NULL) {
|
---|
169 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
|
---|
170 | return NULL;
|
---|
171 | }
|
---|
172 | }
|
---|
173 | /*
|
---|
174 | * If the first file specification is missing, the second one rules.
|
---|
175 | */
|
---|
176 | else if (!filespec1) {
|
---|
177 | merged = OPENSSL_strdup(filespec2);
|
---|
178 | if (merged == NULL) {
|
---|
179 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
|
---|
180 | return NULL;
|
---|
181 | }
|
---|
182 | } else
|
---|
183 | /*
|
---|
184 | * This part isn't as trivial as it looks. It assumes that the
|
---|
185 | * second file specification really is a directory, and makes no
|
---|
186 | * checks whatsoever. Therefore, the result becomes the
|
---|
187 | * concatenation of filespec2 followed by a slash followed by
|
---|
188 | * filespec1.
|
---|
189 | */
|
---|
190 | {
|
---|
191 | int spec2len, len;
|
---|
192 |
|
---|
193 | spec2len = (filespec2 ? strlen(filespec2) : 0);
|
---|
194 | len = spec2len + (filespec1 ? strlen(filespec1) : 0);
|
---|
195 |
|
---|
196 | if (spec2len && filespec2[spec2len - 1] == '/') {
|
---|
197 | spec2len--;
|
---|
198 | len--;
|
---|
199 | }
|
---|
200 | merged = OPENSSL_malloc(len + 2);
|
---|
201 | if (merged == NULL) {
|
---|
202 | ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
|
---|
203 | return NULL;
|
---|
204 | }
|
---|
205 | strcpy(merged, filespec2);
|
---|
206 | merged[spec2len] = '/';
|
---|
207 | strcpy(&merged[spec2len + 1], filespec1);
|
---|
208 | }
|
---|
209 | return merged;
|
---|
210 | }
|
---|
211 |
|
---|
212 | /*
|
---|
213 | * This function is identical to the one in dso_dlfcn.c, but as it is highly
|
---|
214 | * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at
|
---|
215 | * the same time, there's no great duplicating the code. Figuring out an
|
---|
216 | * elegant way to share one copy of the code would be more difficult and
|
---|
217 | * would not leave the implementations independent.
|
---|
218 | */
|
---|
219 | static char *dl_name_converter(DSO *dso, const char *filename)
|
---|
220 | {
|
---|
221 | char *translated;
|
---|
222 | int len, rsize, transform;
|
---|
223 |
|
---|
224 | len = strlen(filename);
|
---|
225 | rsize = len + 1;
|
---|
226 | transform = (strstr(filename, "/") == NULL);
|
---|
227 | if (transform) {
|
---|
228 | /* We will convert this to "%s.s?" or "lib%s.s?" */
|
---|
229 | rsize += strlen(DSO_EXTENSION); /* The length of ".s?" */
|
---|
230 | if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
|
---|
231 | rsize += 3; /* The length of "lib" */
|
---|
232 | }
|
---|
233 | translated = OPENSSL_malloc(rsize);
|
---|
234 | if (translated == NULL) {
|
---|
235 | ERR_raise(ERR_LIB_DSO, DSO_R_NAME_TRANSLATION_FAILED);
|
---|
236 | return NULL;
|
---|
237 | }
|
---|
238 | if (transform) {
|
---|
239 | if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
|
---|
240 | sprintf(translated, "lib%s%s", filename, DSO_EXTENSION);
|
---|
241 | else
|
---|
242 | sprintf(translated, "%s%s", filename, DSO_EXTENSION);
|
---|
243 | } else
|
---|
244 | sprintf(translated, "%s", filename);
|
---|
245 | return translated;
|
---|
246 | }
|
---|
247 |
|
---|
248 | static int dl_pathbyaddr(void *addr, char *path, int sz)
|
---|
249 | {
|
---|
250 | struct shl_descriptor inf;
|
---|
251 | int i, len;
|
---|
252 |
|
---|
253 | if (addr == NULL) {
|
---|
254 | union {
|
---|
255 | int (*f) (void *, char *, int);
|
---|
256 | void *p;
|
---|
257 | } t = {
|
---|
258 | dl_pathbyaddr
|
---|
259 | };
|
---|
260 | addr = t.p;
|
---|
261 | }
|
---|
262 |
|
---|
263 | for (i = -1; shl_get_r(i, &inf) == 0; i++) {
|
---|
264 | if (((size_t)addr >= inf.tstart && (size_t)addr < inf.tend) ||
|
---|
265 | ((size_t)addr >= inf.dstart && (size_t)addr < inf.dend)) {
|
---|
266 | len = (int)strlen(inf.filename);
|
---|
267 | if (sz <= 0)
|
---|
268 | return len + 1;
|
---|
269 | if (len >= sz)
|
---|
270 | len = sz - 1;
|
---|
271 | memcpy(path, inf.filename, len);
|
---|
272 | path[len++] = 0;
|
---|
273 | return len;
|
---|
274 | }
|
---|
275 | }
|
---|
276 |
|
---|
277 | return -1;
|
---|
278 | }
|
---|
279 |
|
---|
280 | static void *dl_globallookup(const char *name)
|
---|
281 | {
|
---|
282 | void *ret;
|
---|
283 | shl_t h = NULL;
|
---|
284 |
|
---|
285 | return shl_findsym(&h, name, TYPE_UNDEFINED, &ret) ? NULL : ret;
|
---|
286 | }
|
---|
287 | #endif /* DSO_DL */
|
---|