/src/openssl30/crypto/dso/dso_dlfcn.c
| Line | Count | Source (jump to first uncovered line) | 
| 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 |  | /* | 
| 11 |  |  * We need to do this early, because stdio.h includes the header files that | 
| 12 |  |  * handle _GNU_SOURCE and other similar macros.  Defining it later is simply | 
| 13 |  |  * too late, because those headers are protected from re- inclusion. | 
| 14 |  |  */ | 
| 15 |  | #ifndef _GNU_SOURCE | 
| 16 |  | # define _GNU_SOURCE            /* make sure dladdr is declared */ | 
| 17 |  | #endif | 
| 18 |  |  | 
| 19 |  | #include "dso_local.h" | 
| 20 |  | #include "e_os.h" | 
| 21 |  |  | 
| 22 |  | #ifdef DSO_DLFCN | 
| 23 |  |  | 
| 24 |  | # ifdef HAVE_DLFCN_H | 
| 25 |  | #  ifdef __osf__ | 
| 26 |  | #   define __EXTENSIONS__ | 
| 27 |  | #  endif | 
| 28 |  | #  include <dlfcn.h> | 
| 29 |  | #  define HAVE_DLINFO 1 | 
| 30 |  | #  if defined(__SCO_VERSION__) || defined(_SCO_ELF) || \ | 
| 31 |  |      (defined(__osf__) && !defined(RTLD_NEXT))     || \ | 
| 32 |  |      (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \ | 
| 33 |  |      defined(__ANDROID__) || defined(__TANDEM) | 
| 34 |  | #   undef HAVE_DLINFO | 
| 35 |  | #  endif | 
| 36 |  | # endif | 
| 37 |  |  | 
| 38 |  | /* Part of the hack in "dlfcn_load" ... */ | 
| 39 |  | # define DSO_MAX_TRANSLATED_SIZE 256 | 
| 40 |  |  | 
| 41 |  | static int dlfcn_load(DSO *dso); | 
| 42 |  | static int dlfcn_unload(DSO *dso); | 
| 43 |  | static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname); | 
| 44 |  | static char *dlfcn_name_converter(DSO *dso, const char *filename); | 
| 45 |  | static char *dlfcn_merger(DSO *dso, const char *filespec1, | 
| 46 |  |                           const char *filespec2); | 
| 47 |  | static int dlfcn_pathbyaddr(void *addr, char *path, int sz); | 
| 48 |  | static void *dlfcn_globallookup(const char *name); | 
| 49 |  |  | 
| 50 |  | static DSO_METHOD dso_meth_dlfcn = { | 
| 51 |  |     "OpenSSL 'dlfcn' shared library method", | 
| 52 |  |     dlfcn_load, | 
| 53 |  |     dlfcn_unload, | 
| 54 |  |     dlfcn_bind_func, | 
| 55 |  |     NULL,                       /* ctrl */ | 
| 56 |  |     dlfcn_name_converter, | 
| 57 |  |     dlfcn_merger, | 
| 58 |  |     NULL,                       /* init */ | 
| 59 |  |     NULL,                       /* finish */ | 
| 60 |  |     dlfcn_pathbyaddr, | 
| 61 |  |     dlfcn_globallookup | 
| 62 |  | }; | 
| 63 |  |  | 
| 64 |  | DSO_METHOD *DSO_METHOD_openssl(void) | 
| 65 | 0 | { | 
| 66 | 0 |     return &dso_meth_dlfcn; | 
| 67 | 0 | } | 
| 68 |  |  | 
| 69 |  | /* | 
| 70 |  |  * Prior to using the dlopen() function, we should decide on the flag we | 
| 71 |  |  * send. There's a few different ways of doing this and it's a messy | 
| 72 |  |  * venn-diagram to match up which platforms support what. So as we don't have | 
| 73 |  |  * autoconf yet, I'm implementing a hack that could be hacked further | 
| 74 |  |  * relatively easily to deal with cases as we find them. Initially this is to | 
| 75 |  |  * cope with OpenBSD. | 
| 76 |  |  */ | 
| 77 |  | # if defined(__OpenBSD__) || defined(__NetBSD__) | 
| 78 |  | #  ifdef DL_LAZY | 
| 79 |  | #   define DLOPEN_FLAG DL_LAZY | 
| 80 |  | #  else | 
| 81 |  | #   ifdef RTLD_NOW | 
| 82 |  | #    define DLOPEN_FLAG RTLD_NOW | 
| 83 |  | #   else | 
| 84 |  | #    define DLOPEN_FLAG 0 | 
| 85 |  | #   endif | 
| 86 |  | #  endif | 
| 87 |  | # else | 
| 88 | 0 | #  define DLOPEN_FLAG RTLD_NOW  /* Hope this works everywhere else */ | 
| 89 |  | # endif | 
| 90 |  |  | 
| 91 |  | /* | 
| 92 |  |  * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle | 
| 93 |  |  * (void*) returned from dlopen(). | 
| 94 |  |  */ | 
| 95 |  |  | 
| 96 |  | static int dlfcn_load(DSO *dso) | 
| 97 | 0 | { | 
| 98 | 0 |     void *ptr = NULL; | 
| 99 |  |     /* See applicable comments in dso_dl.c */ | 
| 100 | 0 |     char *filename = DSO_convert_filename(dso, NULL); | 
| 101 | 0 |     int flags = DLOPEN_FLAG; | 
| 102 | 0 |     int saveerrno = get_last_sys_error(); | 
| 103 |  | 
 | 
| 104 | 0 |     if (filename == NULL) { | 
| 105 | 0 |         ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME); | 
| 106 | 0 |         goto err; | 
| 107 | 0 |     } | 
| 108 | 0 | # ifdef RTLD_GLOBAL | 
| 109 | 0 |     if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS) | 
| 110 | 0 |         flags |= RTLD_GLOBAL; | 
| 111 | 0 | # endif | 
| 112 |  | # ifdef _AIX | 
| 113 |  |     if (filename[strlen(filename) - 1] == ')') | 
| 114 |  |         flags |= RTLD_MEMBER; | 
| 115 |  | # endif | 
| 116 | 0 |     ptr = dlopen(filename, flags); | 
| 117 | 0 |     if (ptr == NULL) { | 
| 118 | 0 |         ERR_raise_data(ERR_LIB_DSO, DSO_R_LOAD_FAILED, | 
| 119 | 0 |                        "filename(%s): %s", filename, dlerror()); | 
| 120 | 0 |         goto err; | 
| 121 | 0 |     } | 
| 122 |  |     /* | 
| 123 |  |      * Some dlopen() implementations (e.g. solaris) do no preserve errno, even | 
| 124 |  |      * on a successful call. | 
| 125 |  |      */ | 
| 126 | 0 |     set_sys_error(saveerrno); | 
| 127 | 0 |     if (!sk_void_push(dso->meth_data, (char *)ptr)) { | 
| 128 | 0 |         ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR); | 
| 129 | 0 |         goto err; | 
| 130 | 0 |     } | 
| 131 |  |     /* Success */ | 
| 132 | 0 |     dso->loaded_filename = filename; | 
| 133 | 0 |     return 1; | 
| 134 | 0 |  err: | 
| 135 |  |     /* Cleanup! */ | 
| 136 | 0 |     OPENSSL_free(filename); | 
| 137 | 0 |     if (ptr != NULL) | 
| 138 | 0 |         dlclose(ptr); | 
| 139 | 0 |     return 0; | 
| 140 | 0 | } | 
| 141 |  |  | 
| 142 |  | static int dlfcn_unload(DSO *dso) | 
| 143 | 0 | { | 
| 144 | 0 |     void *ptr; | 
| 145 | 0 |     if (dso == NULL) { | 
| 146 | 0 |         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); | 
| 147 | 0 |         return 0; | 
| 148 | 0 |     } | 
| 149 | 0 |     if (sk_void_num(dso->meth_data) < 1) | 
| 150 | 0 |         return 1; | 
| 151 | 0 |     ptr = sk_void_pop(dso->meth_data); | 
| 152 | 0 |     if (ptr == NULL) { | 
| 153 | 0 |         ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE); | 
| 154 |  |         /* | 
| 155 |  |          * Should push the value back onto the stack in case of a retry. | 
| 156 |  |          */ | 
| 157 | 0 |         sk_void_push(dso->meth_data, ptr); | 
| 158 | 0 |         return 0; | 
| 159 | 0 |     } | 
| 160 |  |     /* For now I'm not aware of any errors associated with dlclose() */ | 
| 161 | 0 |     dlclose(ptr); | 
| 162 | 0 |     return 1; | 
| 163 | 0 | } | 
| 164 |  |  | 
| 165 |  | static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) | 
| 166 | 0 | { | 
| 167 | 0 |     void *ptr; | 
| 168 | 0 |     union { | 
| 169 | 0 |         DSO_FUNC_TYPE sym; | 
| 170 | 0 |         void *dlret; | 
| 171 | 0 |     } u; | 
| 172 |  | 
 | 
| 173 | 0 |     if ((dso == NULL) || (symname == NULL)) { | 
| 174 | 0 |         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); | 
| 175 | 0 |         return NULL; | 
| 176 | 0 |     } | 
| 177 | 0 |     if (sk_void_num(dso->meth_data) < 1) { | 
| 178 | 0 |         ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR); | 
| 179 | 0 |         return NULL; | 
| 180 | 0 |     } | 
| 181 | 0 |     ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1); | 
| 182 | 0 |     if (ptr == NULL) { | 
| 183 | 0 |         ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE); | 
| 184 | 0 |         return NULL; | 
| 185 | 0 |     } | 
| 186 | 0 |     u.dlret = dlsym(ptr, symname); | 
| 187 | 0 |     if (u.dlret == NULL) { | 
| 188 | 0 |         ERR_raise_data(ERR_LIB_DSO, DSO_R_SYM_FAILURE, | 
| 189 | 0 |                        "symname(%s): %s", symname, dlerror()); | 
| 190 | 0 |         return NULL; | 
| 191 | 0 |     } | 
| 192 | 0 |     return u.sym; | 
| 193 | 0 | } | 
| 194 |  |  | 
| 195 |  | static char *dlfcn_merger(DSO *dso, const char *filespec1, | 
| 196 |  |                           const char *filespec2) | 
| 197 | 0 | { | 
| 198 | 0 |     char *merged; | 
| 199 |  | 
 | 
| 200 | 0 |     if (!filespec1 && !filespec2) { | 
| 201 | 0 |         ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER); | 
| 202 | 0 |         return NULL; | 
| 203 | 0 |     } | 
| 204 |  |     /* | 
| 205 |  |      * If the first file specification is a rooted path, it rules. same goes | 
| 206 |  |      * if the second file specification is missing. | 
| 207 |  |      */ | 
| 208 | 0 |     if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) { | 
| 209 | 0 |         merged = OPENSSL_strdup(filespec1); | 
| 210 | 0 |         if (merged == NULL) { | 
| 211 | 0 |             ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); | 
| 212 | 0 |             return NULL; | 
| 213 | 0 |         } | 
| 214 | 0 |     } | 
| 215 |  |     /* | 
| 216 |  |      * If the first file specification is missing, the second one rules. | 
| 217 |  |      */ | 
| 218 | 0 |     else if (!filespec1) { | 
| 219 | 0 |         merged = OPENSSL_strdup(filespec2); | 
| 220 | 0 |         if (merged == NULL) { | 
| 221 | 0 |             ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); | 
| 222 | 0 |             return NULL; | 
| 223 | 0 |         } | 
| 224 | 0 |     } else { | 
| 225 |  |         /* | 
| 226 |  |          * This part isn't as trivial as it looks.  It assumes that the | 
| 227 |  |          * second file specification really is a directory, and makes no | 
| 228 |  |          * checks whatsoever.  Therefore, the result becomes the | 
| 229 |  |          * concatenation of filespec2 followed by a slash followed by | 
| 230 |  |          * filespec1. | 
| 231 |  |          */ | 
| 232 | 0 |         int spec2len, len; | 
| 233 |  | 
 | 
| 234 | 0 |         spec2len = strlen(filespec2); | 
| 235 | 0 |         len = spec2len + strlen(filespec1); | 
| 236 |  | 
 | 
| 237 | 0 |         if (spec2len && filespec2[spec2len - 1] == '/') { | 
| 238 | 0 |             spec2len--; | 
| 239 | 0 |             len--; | 
| 240 | 0 |         } | 
| 241 | 0 |         merged = OPENSSL_malloc(len + 2); | 
| 242 | 0 |         if (merged == NULL) { | 
| 243 | 0 |             ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE); | 
| 244 | 0 |             return NULL; | 
| 245 | 0 |         } | 
| 246 | 0 |         strcpy(merged, filespec2); | 
| 247 | 0 |         merged[spec2len] = '/'; | 
| 248 | 0 |         strcpy(&merged[spec2len + 1], filespec1); | 
| 249 | 0 |     } | 
| 250 | 0 |     return merged; | 
| 251 | 0 | } | 
| 252 |  |  | 
| 253 |  | static char *dlfcn_name_converter(DSO *dso, const char *filename) | 
| 254 | 0 | { | 
| 255 | 0 |     char *translated; | 
| 256 | 0 |     int len, rsize, transform; | 
| 257 |  | 
 | 
| 258 | 0 |     len = strlen(filename); | 
| 259 | 0 |     rsize = len + 1; | 
| 260 | 0 |     transform = (strstr(filename, "/") == NULL); | 
| 261 | 0 |     if (transform) { | 
| 262 |  |         /* We will convert this to "%s.so" or "lib%s.so" etc */ | 
| 263 | 0 |         rsize += strlen(DSO_EXTENSION);    /* The length of ".so" */ | 
| 264 | 0 |         if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) | 
| 265 | 0 |             rsize += 3;         /* The length of "lib" */ | 
| 266 | 0 |     } | 
| 267 | 0 |     translated = OPENSSL_malloc(rsize); | 
| 268 | 0 |     if (translated == NULL) { | 
| 269 | 0 |         ERR_raise(ERR_LIB_DSO, DSO_R_NAME_TRANSLATION_FAILED); | 
| 270 | 0 |         return NULL; | 
| 271 | 0 |     } | 
| 272 | 0 |     if (transform) { | 
| 273 | 0 |         if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) | 
| 274 | 0 |             sprintf(translated, "lib%s" DSO_EXTENSION, filename); | 
| 275 | 0 |         else | 
| 276 | 0 |             sprintf(translated, "%s" DSO_EXTENSION, filename); | 
| 277 | 0 |     } else | 
| 278 | 0 |         sprintf(translated, "%s", filename); | 
| 279 | 0 |     return translated; | 
| 280 | 0 | } | 
| 281 |  |  | 
| 282 |  | # ifdef __sgi | 
| 283 |  | /*- | 
| 284 |  | This is a quote from IRIX manual for dladdr(3c): | 
| 285 |  |  | 
| 286 |  |      <dlfcn.h> does not contain a prototype for dladdr or definition of | 
| 287 |  |      Dl_info.  The #include <dlfcn.h>  in the SYNOPSIS line is traditional, | 
| 288 |  |      but contains no dladdr prototype and no IRIX library contains an | 
| 289 |  |      implementation.  Write your own declaration based on the code below. | 
| 290 |  |  | 
| 291 |  |      The following code is dependent on internal interfaces that are not | 
| 292 |  |      part of the IRIX compatibility guarantee; however, there is no future | 
| 293 |  |      intention to change this interface, so on a practical level, the code | 
| 294 |  |      below is safe to use on IRIX. | 
| 295 |  | */ | 
| 296 |  | #  include <rld_interface.h> | 
| 297 |  | #  ifndef _RLD_INTERFACE_DLFCN_H_DLADDR | 
| 298 |  | #   define _RLD_INTERFACE_DLFCN_H_DLADDR | 
| 299 |  | typedef struct Dl_info { | 
| 300 |  |     const char *dli_fname; | 
| 301 |  |     void *dli_fbase; | 
| 302 |  |     const char *dli_sname; | 
| 303 |  |     void *dli_saddr; | 
| 304 |  |     int dli_version; | 
| 305 |  |     int dli_reserved1; | 
| 306 |  |     long dli_reserved[4]; | 
| 307 |  | } Dl_info; | 
| 308 |  | #  else | 
| 309 |  | typedef struct Dl_info Dl_info; | 
| 310 |  | #  endif | 
| 311 |  | #  define _RLD_DLADDR             14 | 
| 312 |  |  | 
| 313 |  | static int dladdr(void *address, Dl_info *dl) | 
| 314 |  | { | 
| 315 |  |     void *v; | 
| 316 |  |     v = _rld_new_interface(_RLD_DLADDR, address, dl); | 
| 317 |  |     return (int)v; | 
| 318 |  | } | 
| 319 |  | # endif                         /* __sgi */ | 
| 320 |  |  | 
| 321 |  | # ifdef _AIX | 
| 322 |  | /*- | 
| 323 |  |  * See IBM's AIX Version 7.2, Technical Reference: | 
| 324 |  |  *  Base Operating System and Extensions, Volume 1 and 2 | 
| 325 |  |  *  https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm | 
| 326 |  |  */ | 
| 327 |  | #  include <sys/ldr.h> | 
| 328 |  | #  include <errno.h> | 
| 329 |  | /* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */ | 
| 330 |  | #  define DLFCN_LDINFO_SIZE 86976 | 
| 331 |  | typedef struct Dl_info { | 
| 332 |  |     const char *dli_fname; | 
| 333 |  | } Dl_info; | 
| 334 |  | /* | 
| 335 |  |  * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual | 
| 336 |  |  * address of a function, which is just located in the DATA segment instead of | 
| 337 |  |  * the TEXT segment. | 
| 338 |  |  */ | 
| 339 |  | static int dladdr(void *ptr, Dl_info *dl) | 
| 340 |  | { | 
| 341 |  |     uintptr_t addr = (uintptr_t)ptr; | 
| 342 |  |     unsigned int found = 0; | 
| 343 |  |     struct ld_info *ldinfos, *next_ldi, *this_ldi; | 
| 344 |  |  | 
| 345 |  |     if ((ldinfos = OPENSSL_malloc(DLFCN_LDINFO_SIZE)) == NULL) { | 
| 346 |  |         errno = ENOMEM; | 
| 347 |  |         dl->dli_fname = NULL; | 
| 348 |  |         return 0; | 
| 349 |  |     } | 
| 350 |  |  | 
| 351 |  |     if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) { | 
| 352 |  |         /*- | 
| 353 |  |          * Error handling is done through errno and dlerror() reading errno: | 
| 354 |  |          *  ENOMEM (ldinfos buffer is too small), | 
| 355 |  |          *  EINVAL (invalid flags), | 
| 356 |  |          *  EFAULT (invalid ldinfos ptr) | 
| 357 |  |          */ | 
| 358 |  |         OPENSSL_free((void *)ldinfos); | 
| 359 |  |         dl->dli_fname = NULL; | 
| 360 |  |         return 0; | 
| 361 |  |     } | 
| 362 |  |     next_ldi = ldinfos; | 
| 363 |  |  | 
| 364 |  |     do { | 
| 365 |  |         this_ldi = next_ldi; | 
| 366 |  |         if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg) | 
| 367 |  |              && (addr < ((uintptr_t)this_ldi->ldinfo_textorg + | 
| 368 |  |                          this_ldi->ldinfo_textsize))) | 
| 369 |  |             || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg) | 
| 370 |  |                 && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg + | 
| 371 |  |                             this_ldi->ldinfo_datasize)))) { | 
| 372 |  |             char *buffer, *member; | 
| 373 |  |             size_t buffer_sz, member_len; | 
| 374 |  |  | 
| 375 |  |             buffer_sz = strlen(this_ldi->ldinfo_filename) + 1; | 
| 376 |  |             member = this_ldi->ldinfo_filename + buffer_sz; | 
| 377 |  |             if ((member_len = strlen(member)) > 0) | 
| 378 |  |                 buffer_sz += 1 + member_len + 1; | 
| 379 |  |             found = 1; | 
| 380 |  |             if ((buffer = OPENSSL_malloc(buffer_sz)) != NULL) { | 
| 381 |  |                 OPENSSL_strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz); | 
| 382 |  |                 if (member_len > 0) { | 
| 383 |  |                     /* | 
| 384 |  |                      * Need to respect a possible member name and not just | 
| 385 |  |                      * returning the path name in this case. See docs: | 
| 386 |  |                      * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER. | 
| 387 |  |                      */ | 
| 388 |  |                     OPENSSL_strlcat(buffer, "(", buffer_sz); | 
| 389 |  |                     OPENSSL_strlcat(buffer, member, buffer_sz); | 
| 390 |  |                     OPENSSL_strlcat(buffer, ")", buffer_sz); | 
| 391 |  |                 } | 
| 392 |  |                 dl->dli_fname = buffer; | 
| 393 |  |             } else { | 
| 394 |  |                 errno = ENOMEM; | 
| 395 |  |             } | 
| 396 |  |         } else { | 
| 397 |  |             next_ldi = (struct ld_info *)((uintptr_t)this_ldi + | 
| 398 |  |                                           this_ldi->ldinfo_next); | 
| 399 |  |         } | 
| 400 |  |     } while (this_ldi->ldinfo_next && !found); | 
| 401 |  |     OPENSSL_free((void *)ldinfos); | 
| 402 |  |     return (found && dl->dli_fname != NULL); | 
| 403 |  | } | 
| 404 |  | # endif                         /* _AIX */ | 
| 405 |  |  | 
| 406 |  | static int dlfcn_pathbyaddr(void *addr, char *path, int sz) | 
| 407 | 0 | { | 
| 408 | 0 | # ifdef HAVE_DLINFO | 
| 409 | 0 |     Dl_info dli; | 
| 410 | 0 |     int len; | 
| 411 |  | 
 | 
| 412 | 0 |     if (addr == NULL) { | 
| 413 | 0 |         union { | 
| 414 | 0 |             int (*f) (void *, char *, int); | 
| 415 | 0 |             void *p; | 
| 416 | 0 |         } t = { | 
| 417 | 0 |             dlfcn_pathbyaddr | 
| 418 | 0 |         }; | 
| 419 | 0 |         addr = t.p; | 
| 420 | 0 |     } | 
| 421 |  | 
 | 
| 422 | 0 |     if (dladdr(addr, &dli)) { | 
| 423 | 0 |         len = (int)strlen(dli.dli_fname); | 
| 424 | 0 |         if (sz <= 0) { | 
| 425 |  | #  ifdef _AIX | 
| 426 |  |             OPENSSL_free((void *)dli.dli_fname); | 
| 427 |  | #  endif | 
| 428 | 0 |             return len + 1; | 
| 429 | 0 |         } | 
| 430 | 0 |         if (len >= sz) | 
| 431 | 0 |             len = sz - 1; | 
| 432 | 0 |         memcpy(path, dli.dli_fname, len); | 
| 433 | 0 |         path[len++] = 0; | 
| 434 |  | #  ifdef _AIX | 
| 435 |  |         OPENSSL_free((void *)dli.dli_fname); | 
| 436 |  | #  endif | 
| 437 | 0 |         return len; | 
| 438 | 0 |     } | 
| 439 |  |  | 
| 440 | 0 |     ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror()); | 
| 441 | 0 | # endif | 
| 442 | 0 |     return -1; | 
| 443 | 0 | } | 
| 444 |  |  | 
| 445 |  | static void *dlfcn_globallookup(const char *name) | 
| 446 | 0 | { | 
| 447 | 0 |     void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY); | 
| 448 |  | 
 | 
| 449 | 0 |     if (handle) { | 
| 450 | 0 |         ret = dlsym(handle, name); | 
| 451 | 0 |         dlclose(handle); | 
| 452 | 0 |     } | 
| 453 |  | 
 | 
| 454 | 0 |     return ret; | 
| 455 | 0 | } | 
| 456 |  | #endif                          /* DSO_DLFCN */ |