dso_dlfcn.c 13 KB

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