1 /* 2 * Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (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_locl.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 DSOerr(DSO_F_DL_LOAD, 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 DSOerr(DSO_F_DL_LOAD, DSO_R_LOAD_FAILED); 73 if (openssl_strerror_r(errno, errbuf, sizeof(errbuf))) 74 ERR_add_error_data(4, "filename(", filename, "): ", errbuf); 75 goto err; 76 } 77 if (!sk_push(dso->meth_data, (char *)ptr)) { 78 DSOerr(DSO_F_DL_LOAD, DSO_R_STACK_ERROR); 79 goto err; 80 } 81 /* 82 * Success, stick the converted filename we've loaded under into the DSO 83 * (it also serves as the indicator that we are currently loaded). 84 */ 85 dso->loaded_filename = filename; 86 return 1; 87 err: 88 /* Cleanup! */ 89 OPENSSL_free(filename); 90 if (ptr != NULL) 91 shl_unload(ptr); 92 return 0; 93 } 94 95 static int dl_unload(DSO *dso) 96 { 97 shl_t ptr; 98 if (dso == NULL) { 99 DSOerr(DSO_F_DL_UNLOAD, ERR_R_PASSED_NULL_PARAMETER); 100 return 0; 101 } 102 if (sk_num(dso->meth_data) < 1) 103 return 1; 104 /* Is this statement legal? */ 105 ptr = (shl_t) sk_pop(dso->meth_data); 106 if (ptr == NULL) { 107 DSOerr(DSO_F_DL_UNLOAD, DSO_R_NULL_HANDLE); 108 /* 109 * Should push the value back onto the stack in case of a retry. 110 */ 111 sk_push(dso->meth_data, (char *)ptr); 112 return 0; 113 } 114 shl_unload(ptr); 115 return 1; 116 } 117 118 static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname) 119 { 120 shl_t ptr; 121 void *sym; 122 123 if ((dso == NULL) || (symname == NULL)) { 124 DSOerr(DSO_F_DL_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER); 125 return NULL; 126 } 127 if (sk_num(dso->meth_data) < 1) { 128 DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_STACK_ERROR); 129 return NULL; 130 } 131 ptr = (shl_t) sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); 132 if (ptr == NULL) { 133 DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_NULL_HANDLE); 134 return NULL; 135 } 136 if (shl_findsym(&ptr, symname, TYPE_UNDEFINED, &sym) < 0) { 137 char errbuf[160]; 138 DSOerr(DSO_F_DL_BIND_FUNC, DSO_R_SYM_FAILURE); 139 if (openssl_strerror_r(errno, errbuf, sizeof(errbuf))) 140 ERR_add_error_data(4, "symname(", symname, "): ", errbuf); 141 return NULL; 142 } 143 return (DSO_FUNC_TYPE)sym; 144 } 145 146 static char *dl_merger(DSO *dso, const char *filespec1, const char *filespec2) 147 { 148 char *merged; 149 150 if (!filespec1 && !filespec2) { 151 DSOerr(DSO_F_DL_MERGER, ERR_R_PASSED_NULL_PARAMETER); 152 return NULL; 153 } 154 /* 155 * If the first file specification is a rooted path, it rules. same goes 156 * if the second file specification is missing. 157 */ 158 if (!filespec2 || filespec1[0] == '/') { 159 merged = OPENSSL_strdup(filespec1); 160 if (merged == NULL) { 161 DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE); 162 return NULL; 163 } 164 } 165 /* 166 * If the first file specification is missing, the second one rules. 167 */ 168 else if (!filespec1) { 169 merged = OPENSSL_strdup(filespec2); 170 if (merged == NULL) { 171 DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE); 172 return NULL; 173 } 174 } else 175 /* 176 * This part isn't as trivial as it looks. It assumes that the 177 * second file specification really is a directory, and makes no 178 * checks whatsoever. Therefore, the result becomes the 179 * concatenation of filespec2 followed by a slash followed by 180 * filespec1. 181 */ 182 { 183 int spec2len, len; 184 185 spec2len = (filespec2 ? strlen(filespec2) : 0); 186 len = spec2len + (filespec1 ? strlen(filespec1) : 0); 187 188 if (spec2len && filespec2[spec2len - 1] == '/') { 189 spec2len--; 190 len--; 191 } 192 merged = OPENSSL_malloc(len + 2); 193 if (merged == NULL) { 194 DSOerr(DSO_F_DL_MERGER, ERR_R_MALLOC_FAILURE); 195 return NULL; 196 } 197 strcpy(merged, filespec2); 198 merged[spec2len] = '/'; 199 strcpy(&merged[spec2len + 1], filespec1); 200 } 201 return merged; 202 } 203 204 /* 205 * This function is identical to the one in dso_dlfcn.c, but as it is highly 206 * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at 207 * the same time, there's no great duplicating the code. Figuring out an 208 * elegant way to share one copy of the code would be more difficult and 209 * would not leave the implementations independent. 210 */ 211 static char *dl_name_converter(DSO *dso, const char *filename) 212 { 213 char *translated; 214 int len, rsize, transform; 215 216 len = strlen(filename); 217 rsize = len + 1; 218 transform = (strstr(filename, "/") == NULL); 219 { 220 /* We will convert this to "%s.s?" or "lib%s.s?" */ 221 rsize += strlen(DSO_EXTENSION); /* The length of ".s?" */ 222 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 223 rsize += 3; /* The length of "lib" */ 224 } 225 translated = OPENSSL_malloc(rsize); 226 if (translated == NULL) { 227 DSOerr(DSO_F_DL_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED); 228 return NULL; 229 } 230 if (transform) { 231 if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) 232 sprintf(translated, "lib%s%s", filename, DSO_EXTENSION); 233 else 234 sprintf(translated, "%s%s", filename, DSO_EXTENSION); 235 } else 236 sprintf(translated, "%s", filename); 237 return translated; 238 } 239 240 static int dl_pathbyaddr(void *addr, char *path, int sz) 241 { 242 struct shl_descriptor inf; 243 int i, len; 244 245 if (addr == NULL) { 246 union { 247 int (*f) (void *, char *, int); 248 void *p; 249 } t = { 250 dl_pathbyaddr 251 }; 252 addr = t.p; 253 } 254 255 for (i = -1; shl_get_r(i, &inf) == 0; i++) { 256 if (((size_t)addr >= inf.tstart && (size_t)addr < inf.tend) || 257 ((size_t)addr >= inf.dstart && (size_t)addr < inf.dend)) { 258 len = (int)strlen(inf.filename); 259 if (sz <= 0) 260 return len + 1; 261 if (len >= sz) 262 len = sz - 1; 263 memcpy(path, inf.filename, len); 264 path[len++] = 0; 265 return len; 266 } 267 } 268 269 return -1; 270 } 271 272 static void *dl_globallookup(const char *name) 273 { 274 void *ret; 275 shl_t h = NULL; 276 277 return shl_findsym(&h, name, TYPE_UNDEFINED, &ret) ? NULL : ret; 278 } 279 #endif /* DSO_DL */ 280