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 * 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 * 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 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 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 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 * 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 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 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 * 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 564 _dl_thread_kern_go(lock_cb *cb) 565 { 566 if (cb != NULL) 567 (*cb)(1); 568 } 569 570 int 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 * 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 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