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 */ 288