1 /* $OpenBSD: dlfcn.c,v 1.117 2024/01/22 02:08:31 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 #define _DYN_LOADER
30
31 #include <sys/types.h>
32 #include <link.h>
33 #include <dlfcn.h>
34 #include <unistd.h>
35
36 #include "syscall.h"
37 #include "util.h"
38 #include "resolve.h"
39 #include "archdep.h"
40
41 int _dl_errno;
42
43 static int _dl_real_close(void *handle);
44 static lock_cb *_dl_thread_fnc = NULL;
45 static elf_object_t *obj_from_addr(const void *addr);
46
47 #define OK_FLAGS (0 \
48 | RTLD_TRACE \
49 | RTLD_LAZY \
50 | RTLD_NOW \
51 | RTLD_GLOBAL \
52 | RTLD_NODELETE \
53 | RTLD_NOLOAD \
54 )
55
56 void *
dlopen(const char * libname,int flags)57 dlopen(const char *libname, int flags)
58 {
59 elf_object_t *object;
60 lock_cb *cb;
61 int failed = 0;
62 int obj_flags;
63
64 if (flags & ~OK_FLAGS) {
65 _dl_errno = DL_INVALID_MODE;
66 return NULL;
67 }
68
69 if (libname == NULL)
70 return RTLD_DEFAULT;
71
72 if ((flags & RTLD_TRACE) == RTLD_TRACE) {
73 _dl_traceld = 1;
74 }
75
76 DL_DEB(("dlopen: loading: %s\n", libname));
77
78 cb = _dl_thread_kern_stop();
79
80 if (_dl_debug_map && _dl_debug_map->r_brk) {
81 _dl_debug_map->r_state = RT_ADD;
82 (*((void (*)(void))_dl_debug_map->r_brk))();
83 }
84
85 _dl_loading_object = NULL;
86
87 obj_flags = (flags & RTLD_NOW ? DF_1_NOW : 0)
88 | (flags & RTLD_GLOBAL ? DF_1_GLOBAL : 0)
89 | (flags & RTLD_NOLOAD ? DF_1_NOOPEN : 0)
90 ;
91 object = _dl_load_shlib(libname, _dl_objects, OBJTYPE_DLO, obj_flags, 0);
92 if (object == 0) {
93 DL_DEB(("dlopen: failed to open %s\n", libname));
94 failed = 1;
95 goto loaded;
96 }
97
98 if (flags & RTLD_NODELETE) {
99 object->obj_flags |= DF_1_NODELETE;
100 object->nodelete = 1;
101 }
102
103 _dl_link_dlopen(object);
104
105 if (OBJECT_REF_CNT(object) > 1) {
106 _dl_handle_nodelete(object);
107
108 /* if opened but grpsym_vec has not been filled in */
109 if (object->grpsym_vec.len == 0)
110 _dl_cache_grpsym_list_setup(object);
111 if (_dl_traceld) {
112 _dl_show_objects(object);
113 _dl_unload_shlib(object);
114 _dl_exit(0);
115 }
116 goto loaded;
117 }
118
119 /* this add_object should not be here, XXX */
120 _dl_add_object(object);
121
122 DL_DEB(("head [%s]\n", object->load_name));
123
124 if ((failed = _dl_load_dep_libs(object, obj_flags, 0)) == 1) {
125 _dl_real_close(object);
126 object = NULL;
127 _dl_errno = DL_CANT_LOAD_OBJ;
128 } else {
129 int err;
130 DL_DEB(("tail %s\n", object->load_name));
131 if (_dl_traceld) {
132 _dl_show_objects(object);
133 _dl_unload_shlib(object);
134 _dl_exit(0);
135 }
136 err = _dl_rtld(object);
137 if (err != 0) {
138 _dl_real_close(object);
139 _dl_errno = DL_CANT_LOAD_OBJ;
140 object = NULL;
141 failed = 1;
142 } else {
143 _dl_call_init(object);
144 }
145 }
146
147 loaded:
148 _dl_loading_object = NULL;
149
150 if (_dl_debug_map && _dl_debug_map->r_brk) {
151 _dl_debug_map->r_state = RT_CONSISTENT;
152 (*((void (*)(void))_dl_debug_map->r_brk))();
153 }
154
155 _dl_thread_kern_go(cb);
156
157 DL_DEB(("dlopen: %s: done (%s).\n", libname,
158 failed ? "failed" : "success"));
159
160 return((void *)object);
161 }
162
163 void *
dlsym(void * handle,const char * name)164 dlsym(void *handle, const char *name)
165 {
166 elf_object_t *object;
167 elf_object_t *dynobj;
168 struct sym_res sr;
169 int flags;
170 Elf_Addr addr;
171
172 if (handle == NULL || handle == RTLD_NEXT ||
173 handle == RTLD_SELF || handle == RTLD_DEFAULT) {
174 void *retaddr;
175
176 retaddr = __builtin_return_address(0); /* __GNUC__ only */
177
178 if ((object = obj_from_addr(retaddr)) == NULL) {
179 _dl_errno = DL_CANT_FIND_OBJ;
180 return(0);
181 }
182
183 if (handle == RTLD_NEXT)
184 flags = SYM_SEARCH_NEXT|SYM_PLT;
185 else if (handle == RTLD_SELF)
186 flags = SYM_SEARCH_SELF|SYM_PLT;
187 else if (handle == RTLD_DEFAULT)
188 flags = SYM_SEARCH_ALL|SYM_PLT;
189 else
190 flags = SYM_DLSYM|SYM_PLT;
191
192 } else {
193 object = (elf_object_t *)handle;
194 flags = SYM_DLSYM|SYM_PLT;
195
196 dynobj = _dl_objects;
197 while (dynobj && dynobj != object)
198 dynobj = dynobj->next;
199
200 if (!dynobj || object != dynobj) {
201 _dl_errno = DL_INVALID_HANDLE;
202 return(0);
203 }
204 }
205
206 sr = _dl_find_symbol(name, flags|SYM_NOWARNNOTFOUND, NULL, object);
207 if (sr.sym == NULL) {
208 DL_DEB(("dlsym: failed to find symbol %s\n", name));
209 _dl_errno = DL_NO_SYMBOL;
210 return NULL;
211 }
212
213 addr = sr.obj->obj_base + sr.sym->st_value;
214 #ifdef __hppa__
215 if (ELF_ST_TYPE(sr.sym->st_info) == STT_FUNC)
216 addr = _dl_md_plabel(addr, sr.obj->dyn.pltgot);
217 #endif
218 DL_DEB(("dlsym: %s in %s: %p\n",
219 name, object->load_name, (void *)addr));
220 return (void *)addr;
221 }
222
223 int
dlctl(void * handle,int command,void * data)224 dlctl(void *handle, int command, void *data)
225 {
226 int retval;
227
228 switch (command) {
229 case DL_SETTHREADLCK:
230 DL_DEB(("dlctl: _dl_thread_fnc set to %p\n", data));
231 _dl_thread_fnc = data;
232 retval = 0;
233 break;
234 case DL_SETBINDLCK:
235 /* made superfluous by kbind */
236 retval = 0;
237 break;
238 case DL_REFERENCE:
239 {
240 elf_object_t *obj;
241
242 obj = obj_from_addr(data);
243 if (obj == NULL) {
244 _dl_errno = DL_CANT_FIND_OBJ;
245 retval = -1;
246 break;
247 }
248 if ((obj->status & STAT_NODELETE) == 0) {
249 obj->opencount++;
250 obj->status |= STAT_NODELETE;
251 }
252 retval = 0;
253 break;
254 }
255 case 0x20:
256 _dl_show_objects(NULL);
257 retval = 0;
258 break;
259 case 0x21:
260 {
261 struct object_vector vec;
262 struct dep_node *n, *m;
263 elf_object_t *obj;
264 int i;
265
266 _dl_printf("Load Groups:\n");
267
268 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) {
269 obj = n->data;
270 _dl_printf("%s\n", obj->load_name);
271
272 _dl_printf(" children\n");
273 for (vec = obj->child_vec, i = 0; i < vec.len; i++)
274 _dl_printf("\t[%s]\n", vec.vec[i]->load_name);
275
276 _dl_printf(" grpref\n");
277 TAILQ_FOREACH(m, &obj->grpref_list, next_sib)
278 _dl_printf("\t[%s]\n", m->data->load_name);
279 _dl_printf("\n");
280 }
281 retval = 0;
282 break;
283 }
284 default:
285 _dl_errno = DL_INVALID_CTL;
286 retval = -1;
287 break;
288 }
289 return (retval);
290 }
291 __strong_alias(_dlctl,dlctl);
292
293 int
dlclose(void * handle)294 dlclose(void *handle)
295 {
296 lock_cb *cb;
297 int retval;
298
299 if (handle == RTLD_DEFAULT)
300 return 0;
301
302 cb = _dl_thread_kern_stop();
303
304 if (_dl_debug_map && _dl_debug_map->r_brk) {
305 _dl_debug_map->r_state = RT_DELETE;
306 (*((void (*)(void))_dl_debug_map->r_brk))();
307 }
308
309 retval = _dl_real_close(handle);
310
311 if (_dl_debug_map && _dl_debug_map->r_brk) {
312 _dl_debug_map->r_state = RT_CONSISTENT;
313 (*((void (*)(void))_dl_debug_map->r_brk))();
314 }
315 _dl_thread_kern_go(cb);
316 return (retval);
317 }
318
319 int
_dl_real_close(void * handle)320 _dl_real_close(void *handle)
321 {
322 elf_object_t *object;
323 elf_object_t *dynobj;
324
325 object = (elf_object_t *)handle;
326
327 dynobj = _dl_objects;
328 while (dynobj && dynobj != object)
329 dynobj = dynobj->next;
330
331 if (!dynobj || object != dynobj) {
332 _dl_errno = DL_INVALID_HANDLE;
333 return (1);
334 }
335
336 if (object->opencount == 0) {
337 _dl_errno = DL_INVALID_HANDLE;
338 return (1);
339 }
340
341 object->opencount--;
342 _dl_notify_unload_shlib(object);
343 _dl_run_all_dtors();
344 _dl_unload_shlib(object);
345 _dl_cleanup_objects();
346 return (0);
347 }
348
349
350 /*
351 * Return a character string describing the last dl... error occurred.
352 */
353 char *
dlerror(void)354 dlerror(void)
355 {
356 char *errmsg;
357
358 switch (_dl_errno) {
359 case 0: /* NO ERROR */
360 errmsg = NULL;
361 break;
362 case DL_NOT_FOUND:
363 errmsg = "File not found";
364 break;
365 case DL_CANT_OPEN:
366 errmsg = "Can't open file";
367 break;
368 case DL_NOT_ELF:
369 errmsg = "File not an ELF object";
370 break;
371 case DL_CANT_OPEN_REF:
372 errmsg = "Can't open referenced object";
373 break;
374 case DL_CANT_MMAP:
375 errmsg = "Can't map ELF object";
376 break;
377 case DL_INVALID_HANDLE:
378 errmsg = "Invalid handle";
379 break;
380 case DL_NO_SYMBOL:
381 errmsg = "Unable to resolve symbol";
382 break;
383 case DL_INVALID_CTL:
384 errmsg = "Invalid dlctl() command";
385 break;
386 case DL_NO_OBJECT:
387 errmsg = "No shared object contains address";
388 break;
389 case DL_CANT_FIND_OBJ:
390 errmsg = "Cannot determine caller's shared object";
391 break;
392 case DL_CANT_LOAD_OBJ:
393 errmsg = "Cannot load specified object";
394 break;
395 case DL_INVALID_MODE:
396 errmsg = "Invalid mode";
397 break;
398 default:
399 errmsg = "Unknown error";
400 }
401
402 _dl_errno = 0;
403 return (errmsg);
404 }
405
406 static void
_dl_tracefmt(int fd,elf_object_t * object,const char * fmt1,const char * fmt2,const char * objtypename)407 _dl_tracefmt(int fd, elf_object_t *object, const char *fmt1, const char *fmt2,
408 const char *objtypename)
409 {
410 const char *fmt;
411 int i;
412
413 fmt = object->sod.sod_library ? fmt1 : fmt2;
414
415 for (i = 0; fmt[i]; i++) {
416 if (fmt[i] != '%' && fmt[i] != '\\') {
417 _dl_dprintf(fd, "%c", fmt[i]);
418 continue;
419 }
420 if (fmt[i] == '%') {
421 i++;
422 switch (fmt[i]) {
423 case '\0':
424 return;
425 case '%':
426 _dl_dprintf(fd, "%c", '%');
427 break;
428 case 'A':
429 _dl_dprintf(fd, "%s", _dl_traceprog ?
430 _dl_traceprog : "");
431 break;
432 case 'a':
433 _dl_dprintf(fd, "%s", __progname);
434 break;
435 case 'e':
436 _dl_dprintf(fd, "%lX",
437 (void *)(object->load_base +
438 object->load_size));
439 break;
440 case 'g':
441 _dl_dprintf(fd, "%d", object->grprefcount);
442 break;
443 case 'm':
444 _dl_dprintf(fd, "%d", object->sod.sod_major);
445 break;
446 case 'n':
447 _dl_dprintf(fd, "%d", object->sod.sod_minor);
448 break;
449 case 'O':
450 _dl_dprintf(fd, "%d", object->opencount);
451 break;
452 case 'o':
453 _dl_dprintf(fd, "%s", object->sod.sod_name);
454 break;
455 case 'p':
456 _dl_dprintf(fd, "%s", object->load_name);
457 break;
458 case 'r':
459 _dl_dprintf(fd, "%d", object->refcount);
460 break;
461 case 't':
462 _dl_dprintf(fd, "%s", objtypename);
463 break;
464 case 'x':
465 _dl_dprintf(fd, "%lX", object->load_base);
466 break;
467 }
468 }
469 if (fmt[i] == '\\') {
470 i++;
471 switch (fmt[i]) {
472 case '\0':
473 return;
474 case 'n':
475 _dl_dprintf(fd, "%c", '\n');
476 break;
477 case 'r':
478 _dl_dprintf(fd, "%c", '\r');
479 break;
480 case 't':
481 _dl_dprintf(fd, "%c", '\t');
482 break;
483 default:
484 _dl_dprintf(fd, "%c", fmt[i]);
485 break;
486 }
487 }
488 }
489 }
490
491 void
_dl_show_objects(elf_object_t * trace)492 _dl_show_objects(elf_object_t *trace)
493 {
494 elf_object_t *object;
495 char *objtypename;
496 int outputfd;
497 char *pad;
498 const char *fmt1, *fmt2;
499
500 object = _dl_objects;
501 if (_dl_traceld)
502 outputfd = STDOUT_FILENO;
503 else
504 outputfd = STDERR_FILENO;
505
506 if (sizeof(long) == 8)
507 pad = " ";
508 else
509 pad = "";
510
511 fmt1 = _dl_tracefmt1 ? _dl_tracefmt1 :
512 "\t%x %e %t %O %r %g %p\n";
513 fmt2 = _dl_tracefmt2 ? _dl_tracefmt2 :
514 "\t%x %e %t %O %r %g %p\n";
515
516 if (_dl_tracefmt1 == NULL && _dl_tracefmt2 == NULL)
517 _dl_dprintf(outputfd, "\tStart %s End %s Type Open Ref GrpRef Name\n",
518 pad, pad);
519
520 if (trace != NULL) {
521 for (; object != NULL; object = object->next) {
522 if (object == trace)
523 break;
524 if (object->obj_type == OBJTYPE_LDR) {
525 object = object->next;
526 break;
527 }
528 }
529 }
530
531 for (; object != NULL; object = object->next) {
532 switch (object->obj_type) {
533 case OBJTYPE_LDR:
534 objtypename = "ld.so";
535 break;
536 case OBJTYPE_EXE:
537 objtypename = "exe ";
538 break;
539 case OBJTYPE_LIB:
540 objtypename = "rlib ";
541 break;
542 case OBJTYPE_DLO:
543 objtypename = "dlib ";
544 break;
545 default:
546 objtypename = "?????";
547 break;
548 }
549 _dl_tracefmt(outputfd, object, fmt1, fmt2, objtypename);
550 }
551 }
552
553 lock_cb *
_dl_thread_kern_stop(void)554 _dl_thread_kern_stop(void)
555 {
556 lock_cb *cb = _dl_thread_fnc;
557
558 if (cb != NULL)
559 (*cb)(0);
560 return cb;
561 }
562
563 void
_dl_thread_kern_go(lock_cb * cb)564 _dl_thread_kern_go(lock_cb *cb)
565 {
566 if (cb != NULL)
567 (*cb)(1);
568 }
569
570 int
dl_iterate_phdr(int (* callback)(struct dl_phdr_info *,size_t,void * data),void * data)571 dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *data),
572 void *data)
573 {
574 elf_object_t *object;
575 struct dl_phdr_info info;
576 int retval = -1;
577
578 for (object = _dl_objects; object != NULL; object = object->next) {
579 if (object->phdrp == NULL)
580 continue;
581
582 info.dlpi_addr = object->obj_base;
583 info.dlpi_name = object->load_name;
584 info.dlpi_phdr = object->phdrp;
585 info.dlpi_phnum = object->phdrc;
586 retval = callback(&info, sizeof (struct dl_phdr_info), data);
587 if (retval)
588 break;
589 }
590
591 return retval;
592 }
593
594 static elf_object_t *
obj_from_addr(const void * addr)595 obj_from_addr(const void *addr)
596 {
597 elf_object_t *dynobj;
598 Elf_Phdr *phdrp;
599 int phdrc;
600 Elf_Addr start;
601 int i;
602
603 for (dynobj = _dl_objects; dynobj != NULL; dynobj = dynobj->next) {
604 if (dynobj->phdrp == NULL)
605 continue;
606
607 phdrp = dynobj->phdrp;
608 phdrc = dynobj->phdrc;
609
610 for (i = 0; i < phdrc; i++, phdrp++) {
611 if (phdrp->p_type == PT_LOAD) {
612 start = dynobj->obj_base + phdrp->p_vaddr;
613 if ((Elf_Addr)addr >= start &&
614 (Elf_Addr)addr < start + phdrp->p_memsz)
615 return dynobj;
616 }
617 }
618 }
619
620 return NULL;
621 }
622
623 int
dladdr(const void * addr,Dl_info * info)624 dladdr(const void *addr, Dl_info *info)
625 {
626 const elf_object_t *object;
627 const Elf_Sym *sym;
628 void *symbol_addr;
629 u_int32_t symoffset;
630
631 object = obj_from_addr(addr);
632
633 if (object == NULL) {
634 _dl_errno = DL_NO_OBJECT;
635 return 0;
636 }
637
638 info->dli_fname = (char *)object->load_name;
639 info->dli_fbase = (void *)object->load_base;
640 info->dli_sname = NULL;
641 info->dli_saddr = NULL;
642
643 /*
644 * Walk the symbol list looking for the symbol whose address is
645 * closest to the address sent in.
646 */
647 for (symoffset = 0; symoffset < object->nchains; symoffset++) {
648 sym = object->dyn.symtab + symoffset;
649
650 /*
651 * For skip the symbol if st_shndx is either SHN_UNDEF or
652 * SHN_COMMON.
653 */
654 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_COMMON)
655 continue;
656
657 /*
658 * If the symbol is greater than the specified address, or if
659 * it is further away from addr than the current nearest
660 * symbol, then reject it.
661 */
662 symbol_addr = (void *)(object->obj_base + sym->st_value);
663 if (symbol_addr > addr || symbol_addr < info->dli_saddr)
664 continue;
665
666 /* Update our idea of the nearest symbol. */
667 info->dli_sname = object->dyn.strtab + sym->st_name;
668 info->dli_saddr = symbol_addr;
669
670 /* Exact match? */
671 if (info->dli_saddr == addr)
672 break;
673 }
674
675 return 1;
676 }
677