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