resolve.c revision 1.101
1/* $OpenBSD: resolve.c,v 1.101 2024/01/16 19:07: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 <sys/mman.h> 33#include <sys/syscall.h> 34 35#include <limits.h> 36#include <link.h> 37 38#include "util.h" 39#include "path.h" 40#include "resolve.h" 41#include "syscall.h" 42 43/* substitution types */ 44typedef enum { 45 SUBST_UNKNOWN, SUBST_ORIGIN, SUBST_OSNAME, SUBST_OSREL, SUBST_PLATFORM 46} SUBST_TYPES; 47 48struct symlookup { 49 const char *sl_name; 50 struct sym_res sl_out; 51 struct sym_res sl_weak_out; 52 unsigned long sl_elf_hash; 53 uint32_t sl_gnu_hash; 54 int sl_flags; 55}; 56 57elf_object_t *_dl_objects; 58int object_count; 59static elf_object_t *_dl_last_object; 60elf_object_t *_dl_loading_object; 61 62void 63_dl_handle_nodelete(elf_object_t *object) 64{ 65 /* 66 * If a .so is marked nodelete, then the entire load group that it's 67 * in needs to be kept around forever, so add a reference there. 68 * XXX It would be better if we tracked inter-object dependencies 69 * from relocations and didn't leave dangling pointers when a load 70 * group was partially unloaded. That would render this unnecessary. 71 */ 72 if (object->obj_flags & DF_1_NODELETE && 73 (object->load_object->status & STAT_NODELETE) == 0) { 74 DL_DEB(("objname %s is nodelete\n", object->load_name)); 75 object->load_object->opencount++; 76 object->load_object->status |= STAT_NODELETE; 77 } 78} 79 80/* 81 * Add a new dynamic object to the object list. 82 */ 83void 84_dl_add_object(elf_object_t *object) 85{ 86 _dl_handle_nodelete(object); 87 88 /* 89 * if this is a new object, prev will be NULL 90 * != NULL if an object already in the list 91 * prev == NULL for the first item in the list, but that will 92 * be the executable. 93 */ 94 if (object->prev != NULL) 95 return; 96 97 if (_dl_objects == NULL) { /* First object ? */ 98 _dl_last_object = _dl_objects = object; 99 object_count = 2; /* count ld.so early */ 100 } else { 101 _dl_last_object->next = object; 102 object->prev = _dl_last_object; 103 _dl_last_object = object; 104 if (object->obj_type != OBJTYPE_LDR) /* see above */ 105 object_count++; 106 } 107} 108 109/* 110 * Identify substitution sequence name. 111 */ 112static int 113_dl_subst_name(const char *name, size_t siz) { 114 switch (siz) { 115 case 5: 116 if (_dl_strncmp(name, "OSREL", 5) == 0) 117 return SUBST_OSREL; 118 break; 119 case 6: 120 if (_dl_strncmp(name, "ORIGIN", 6) == 0) 121 return SUBST_ORIGIN; 122 if (_dl_strncmp(name, "OSNAME", 6) == 0) 123 return SUBST_OSNAME; 124 break; 125 case 8: 126 if (_dl_strncmp(name, "PLATFORM", 8) == 0) 127 return SUBST_PLATFORM; 128 break; 129 } 130 131 return (SUBST_UNKNOWN); 132} 133 134/* 135 * Perform $ORIGIN substitutions on path 136 */ 137static void 138_dl_origin_subst_path(elf_object_t *object, const char *origin_path, 139 char **path) 140{ 141 char tmp_path[PATH_MAX]; 142 char *new_path, *tp; 143 const char *pp, *name, *value; 144 static struct utsname uts; 145 size_t value_len; 146 int skip_brace; 147 148 if (uts.sysname[0] == '\0') { 149 if (_dl_uname(&uts) != 0) 150 return; 151 } 152 153 tp = tmp_path; 154 pp = *path; 155 156 while (*pp != '\0' && (tp - tmp_path) < sizeof(tmp_path)) { 157 158 /* copy over chars up to but not including $ */ 159 while (*pp != '\0' && *pp != '$' && 160 (tp - tmp_path) < sizeof(tmp_path)) 161 *tp++ = *pp++; 162 163 /* substitution sequence detected */ 164 if (*pp == '$' && (tp - tmp_path) < sizeof(tmp_path)) { 165 pp++; 166 167 if ((skip_brace = (*pp == '{'))) 168 pp++; 169 170 /* skip over name */ 171 name = pp; 172 while (_dl_isalnum((unsigned char)*pp) || *pp == '_') 173 pp++; 174 175 switch (_dl_subst_name(name, pp - name)) { 176 case SUBST_ORIGIN: 177 value = origin_path; 178 break; 179 case SUBST_OSNAME: 180 value = uts.sysname; 181 break; 182 case SUBST_OSREL: 183 value = uts.release; 184 break; 185 case SUBST_PLATFORM: 186 value = uts.machine; 187 break; 188 default: 189 value = ""; 190 } 191 192 value_len = _dl_strlen(value); 193 if (value_len >= sizeof(tmp_path) - (tp - tmp_path)) 194 return; 195 196 _dl_bcopy(value, tp, value_len); 197 tp += value_len; 198 199 if (skip_brace && *pp == '}') 200 pp++; 201 } 202 } 203 204 /* no substitution made if result exceeds sizeof(tmp_path) */ 205 if (tp - tmp_path >= sizeof(tmp_path)) 206 return; 207 208 /* NULL terminate tmp_path */ 209 *tp = '\0'; 210 211 if (_dl_strcmp(tmp_path, *path) == 0) 212 return; 213 214 new_path = _dl_strdup(tmp_path); 215 if (new_path == NULL) 216 return; 217 218 DL_DEB(("orig_path %s\n", *path)); 219 DL_DEB(("new_path %s\n", new_path)); 220 221 _dl_free(*path); 222 *path = new_path; 223} 224 225/* 226 * Determine origin_path from object load_name. The origin_path argument 227 * must refer to a buffer capable of storing at least PATH_MAX characters. 228 * Returns 0 on success. 229 */ 230static int 231_dl_origin_path(elf_object_t *object, char *origin_path) 232{ 233 const char *dirname_path; 234 235 /* syscall in ld.so returns 0/-errno, where libc returns char* */ 236 if (_dl___realpath(object->load_name, origin_path) < 0) 237 return -1; 238 239 dirname_path = _dl_dirname(origin_path); 240 if (dirname_path == NULL) 241 return -1; 242 243 _dl_strlcpy(origin_path, dirname_path, PATH_MAX); 244 245 return 0; 246} 247 248/* 249 * Perform $ORIGIN substitutions on runpath and rpath 250 */ 251static void 252_dl_origin_subst(elf_object_t *object) 253{ 254 char origin_path[PATH_MAX]; 255 char **pp; 256 257 if (_dl_origin_path(object, origin_path) != 0) 258 return; 259 260 /* perform path substitutions on each segment of runpath and rpath */ 261 if (object->runpath != NULL) { 262 for (pp = object->runpath; *pp != NULL; pp++) 263 _dl_origin_subst_path(object, origin_path, pp); 264 } 265 if (object->rpath != NULL) { 266 for (pp = object->rpath; *pp != NULL; pp++) 267 _dl_origin_subst_path(object, origin_path, pp); 268 } 269} 270 271/* 272 * Initialize a new dynamic object. 273 */ 274elf_object_t * 275_dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, 276 int phdrc, const int objtype, const long lbase, const long obase) 277{ 278 elf_object_t *object; 279 Elf_Addr gnu_hash = 0; 280 281 DL_DEB(("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n", 282 objname, dynp, objtype, lbase, obase)); 283 284 object = _dl_calloc(1, sizeof(elf_object_t)); 285 if (object == NULL) 286 _dl_oom(); 287 object->prev = object->next = NULL; 288 289 object->load_dyn = dynp; 290 while (dynp->d_tag != DT_NULL) { 291 if (dynp->d_tag < DT_NUM) 292 object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val; 293 else if (dynp->d_tag >= DT_LOPROC && 294 dynp->d_tag < DT_LOPROC + DT_PROCNUM) 295 object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] = 296 dynp->d_un.d_val; 297 if (dynp->d_tag == DT_TEXTREL) 298 object->dyn.textrel = 1; 299 if (dynp->d_tag == DT_SYMBOLIC) 300 object->dyn.symbolic = 1; 301 if (dynp->d_tag == DT_BIND_NOW) 302 object->obj_flags |= DF_1_NOW; 303 if (dynp->d_tag == DT_FLAGS_1) 304 object->obj_flags |= dynp->d_un.d_val; 305 if (dynp->d_tag == DT_FLAGS) { 306 object->dyn.flags |= dynp->d_un.d_val; 307 if (dynp->d_un.d_val & DF_SYMBOLIC) 308 object->dyn.symbolic = 1; 309 if (dynp->d_un.d_val & DF_TEXTREL) 310 object->dyn.textrel = 1; 311 if (dynp->d_un.d_val & DF_ORIGIN) 312 object->obj_flags |= DF_1_ORIGIN; 313 if (dynp->d_un.d_val & DF_BIND_NOW) 314 object->obj_flags |= DF_1_NOW; 315 } 316 if (dynp->d_tag == DT_RELACOUNT) 317 object->relacount = dynp->d_un.d_val; 318 if (dynp->d_tag == DT_RELCOUNT) 319 object->relcount = dynp->d_un.d_val; 320 if (dynp->d_tag == DT_GNU_HASH) 321 gnu_hash = dynp->d_un.d_val; 322 dynp++; 323 } 324 DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags )); 325 object->obj_type = objtype; 326 327 if (_dl_loading_object == NULL) { 328 /* 329 * no loading object, object is the loading object, 330 * as it is either executable, or dlopened() 331 */ 332 _dl_loading_object = object; 333 } 334 335 if ((object->obj_flags & DF_1_NOOPEN) != 0 && 336 _dl_loading_object->obj_type == OBJTYPE_DLO && 337 !_dl_traceld) { 338 _dl_free(object); 339 _dl_errno = DL_CANT_LOAD_OBJ; 340 return(NULL); 341 } 342 343 /* 344 * Now relocate all pointer to dynamic info, but only 345 * the ones which have pointer values. 346 */ 347 if (object->Dyn.info[DT_PLTGOT]) 348 object->Dyn.info[DT_PLTGOT] += obase; 349 if (object->Dyn.info[DT_STRTAB]) 350 object->Dyn.info[DT_STRTAB] += obase; 351 if (object->Dyn.info[DT_SYMTAB]) 352 object->Dyn.info[DT_SYMTAB] += obase; 353 if (object->Dyn.info[DT_RELA]) 354 object->Dyn.info[DT_RELA] += obase; 355 if (object->Dyn.info[DT_SONAME]) 356 object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB]; 357 if (object->Dyn.info[DT_RPATH]) 358 object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB]; 359 if (object->Dyn.info[DT_RUNPATH]) 360 object->Dyn.info[DT_RUNPATH] += object->Dyn.info[DT_STRTAB]; 361 if (object->Dyn.info[DT_REL]) 362 object->Dyn.info[DT_REL] += obase; 363 if (object->Dyn.info[DT_INIT]) 364 object->Dyn.info[DT_INIT] += obase; 365 if (object->Dyn.info[DT_FINI]) 366 object->Dyn.info[DT_FINI] += obase; 367 if (object->Dyn.info[DT_JMPREL]) 368 object->Dyn.info[DT_JMPREL] += obase; 369 if (object->Dyn.info[DT_INIT_ARRAY]) 370 object->Dyn.info[DT_INIT_ARRAY] += obase; 371 if (object->Dyn.info[DT_FINI_ARRAY]) 372 object->Dyn.info[DT_FINI_ARRAY] += obase; 373 if (object->Dyn.info[DT_PREINIT_ARRAY]) 374 object->Dyn.info[DT_PREINIT_ARRAY] += obase; 375 if (object->Dyn.info[DT_RELR]) 376 object->Dyn.info[DT_RELR] += obase; 377 378 if (gnu_hash) { 379 Elf_Word *hashtab = (Elf_Word *)(gnu_hash + obase); 380 Elf_Word nbuckets = hashtab[0]; 381 Elf_Word nmaskwords = hashtab[2]; 382 383 /* validity check */ 384 if (nbuckets > 0 && (nmaskwords & (nmaskwords - 1)) == 0) { 385 Elf_Word symndx = hashtab[1]; 386 int bloom_size32 = (ELFSIZE / 32) * nmaskwords; 387 388 object->nbuckets = nbuckets; 389 object->symndx_gnu = symndx; 390 object->mask_bm_gnu = nmaskwords - 1; 391 object->shift2_gnu = hashtab[3]; 392 object->bloom_gnu = (Elf_Addr *)(hashtab + 4); 393 object->buckets_gnu = hashtab + 4 + bloom_size32; 394 object->chains_gnu = object->buckets_gnu + nbuckets 395 - symndx; 396 397 /* 398 * If the ELF hash is present, get the total symbol 399 * count ("nchains") from there. Otherwise, count 400 * the entries in the GNU hash chain. 401 */ 402 if (object->Dyn.info[DT_HASH] == 0) { 403 Elf_Word n; 404 405 for (n = 0; n < nbuckets; n++) { 406 Elf_Word bkt = object->buckets_gnu[n]; 407 const Elf_Word *hashval; 408 if (bkt == 0) 409 continue; 410 hashval = &object->chains_gnu[bkt]; 411 do { 412 symndx++; 413 } while ((*hashval++ & 1U) == 0); 414 } 415 object->nchains = symndx; 416 } 417 object->status |= STAT_GNU_HASH; 418 } 419 } 420 if (object->Dyn.info[DT_HASH] != 0) { 421 Elf_Hash_Word *hashtab = 422 (Elf_Hash_Word *)(object->Dyn.info[DT_HASH] + obase); 423 424 object->nchains = hashtab[1]; 425 if (object->nbuckets == 0) { 426 object->nbuckets = hashtab[0]; 427 object->buckets_elf = hashtab + 2; 428 object->chains_elf = object->buckets_elf + 429 object->nbuckets; 430 } 431 } 432 433 object->phdrp = phdrp; 434 object->phdrc = phdrc; 435 object->load_base = lbase; 436 object->obj_base = obase; 437 object->load_name = _dl_strdup(objname); 438 if (object->load_name == NULL) 439 _dl_oom(); 440 object->load_object = _dl_loading_object; 441 if (object->load_object == object) 442 DL_DEB(("head %s\n", object->load_name)); 443 DL_DEB(("obj %s has %s as head\n", object->load_name, 444 _dl_loading_object->load_name )); 445 object->refcount = 0; 446 object->opencount = 0; /* # dlopen() & exe */ 447 object->grprefcount = 0; 448 /* default dev, inode for dlopen-able objects. */ 449 object->dev = 0; 450 object->inode = 0; 451 object->grpsym_gen = 0; 452 TAILQ_INIT(&object->grpref_list); 453 454 if (object->dyn.runpath) 455 object->runpath = _dl_split_path(object->dyn.runpath); 456 /* 457 * DT_RPATH is ignored if DT_RUNPATH is present...except in 458 * the exe, whose DT_RPATH is a fallback for libs that don't 459 * use DT_RUNPATH 460 */ 461 if (object->dyn.rpath && (object->runpath == NULL || 462 objtype == OBJTYPE_EXE)) 463 object->rpath = _dl_split_path(object->dyn.rpath); 464 if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust) 465 _dl_origin_subst(object); 466 467 _dl_trace_object_setup(object); 468 469 return (object); 470} 471 472static void 473_dl_tailq_free(struct dep_node *n) 474{ 475 struct dep_node *next; 476 477 while (n != NULL) { 478 next = TAILQ_NEXT(n, next_sib); 479 _dl_free(n); 480 n = next; 481 } 482} 483 484static elf_object_t *free_objects; 485 486void 487_dl_cleanup_objects() 488{ 489 elf_object_t *nobj, *head; 490 struct dep_node *n, *next; 491 492 n = TAILQ_FIRST(&_dlopened_child_list); 493 while (n != NULL) { 494 next = TAILQ_NEXT(n, next_sib); 495 if (OBJECT_DLREF_CNT(n->data) == 0) { 496 TAILQ_REMOVE(&_dlopened_child_list, n, next_sib); 497 _dl_free(n); 498 } 499 n = next; 500 } 501 502 head = free_objects; 503 free_objects = NULL; 504 while (head != NULL) { 505 _dl_free(head->load_name); 506 _dl_free((char *)head->sod.sod_name); 507 _dl_free_path(head->runpath); 508 _dl_free_path(head->rpath); 509 _dl_free(head->grpsym_vec.vec); 510 _dl_free(head->child_vec.vec); 511 _dl_tailq_free(TAILQ_FIRST(&head->grpref_list)); 512 nobj = head->next; 513 _dl_free(head); 514 head = nobj; 515 } 516} 517 518void 519_dl_remove_object(elf_object_t *object) 520{ 521 object->prev->next = object->next; 522 if (object->next) 523 object->next->prev = object->prev; 524 525 if (_dl_last_object == object) 526 _dl_last_object = object->prev; 527 object_count--; 528 529 object->next = free_objects; 530 free_objects = object; 531} 532 533static int 534matched_symbol(elf_object_t *obj, const Elf_Sym *sym, struct symlookup *sl) 535{ 536 switch (ELF_ST_TYPE(sym->st_info)) { 537 case STT_FUNC: 538 /* 539 * Allow this symbol if we are referring to a function which 540 * has a value, even if section is UNDEF. This allows &func 541 * to refer to PLT as per the ELF spec. If flags has SYM_PLT 542 * set, we must have actual symbol, so this symbol is skipped. 543 */ 544 if ((sl->sl_flags & SYM_PLT) && sym->st_shndx == SHN_UNDEF) 545 return 0; 546 if (sym->st_value == 0) 547 return 0; 548 break; 549 case STT_NOTYPE: 550 case STT_OBJECT: 551 if (sym->st_value == 0) 552 return 0; 553#if 0 554 /* FALLTHROUGH */ 555 case STT_TLS: 556#endif 557 if (sym->st_shndx == SHN_UNDEF) 558 return 0; 559 break; 560 default: 561 return 0; 562 } 563 564 if (sym != sl->sl_out.sym && 565 _dl_strcmp(sl->sl_name, obj->dyn.strtab + sym->st_name)) 566 return 0; 567 568 if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) { 569 sl->sl_out.sym = sym; 570 sl->sl_out.obj = obj; 571 return 1; 572 } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 573 if (sl->sl_weak_out.sym == NULL) { 574 sl->sl_weak_out.sym = sym; 575 sl->sl_weak_out.obj = obj; 576 } 577 /* done with this object, but need to check other objects */ 578 return -1; 579 } 580 return 0; 581} 582 583static int 584_dl_find_symbol_obj(elf_object_t *obj, struct symlookup *sl) 585{ 586 const Elf_Sym *symt = obj->dyn.symtab; 587 588 if (obj->status & STAT_GNU_HASH) { 589 uint32_t hash = sl->sl_gnu_hash; 590 Elf_Addr bloom_word; 591 unsigned int h1; 592 unsigned int h2; 593 Elf_Word bucket; 594 const Elf_Word *hashval; 595 596 /* pick right bitmask word from Bloom filter array */ 597 bloom_word = obj->bloom_gnu[(hash / ELFSIZE) & 598 obj->mask_bm_gnu]; 599 600 /* calculate modulus ELFSIZE of gnu hash and its derivative */ 601 h1 = hash & (ELFSIZE - 1); 602 h2 = (hash >> obj->shift2_gnu) & (ELFSIZE - 1); 603 604 /* Filter out the "definitely not in set" queries */ 605 if (((bloom_word >> h1) & (bloom_word >> h2) & 1) == 0) 606 return 0; 607 608 /* Locate hash chain and corresponding value element */ 609 bucket = obj->buckets_gnu[hash % obj->nbuckets]; 610 if (bucket == 0) 611 return 0; 612 hashval = &obj->chains_gnu[bucket]; 613 do { 614 if (((*hashval ^ hash) >> 1) == 0) { 615 const Elf_Sym *sym = symt + 616 (hashval - obj->chains_gnu); 617 618 int r = matched_symbol(obj, sym, sl); 619 if (r) 620 return r > 0; 621 } 622 } while ((*hashval++ & 1U) == 0); 623 } else { 624 Elf_Word si; 625 626 for (si = obj->buckets_elf[sl->sl_elf_hash % obj->nbuckets]; 627 si != STN_UNDEF; si = obj->chains_elf[si]) { 628 const Elf_Sym *sym = symt + si; 629 630 int r = matched_symbol(obj, sym, sl); 631 if (r) 632 return r > 0; 633 } 634 } 635 return 0; 636} 637 638struct sym_res 639_dl_find_symbol(const char *name, int flags, const Elf_Sym *ref_sym, 640 elf_object_t *req_obj) 641{ 642 const unsigned char *p; 643 unsigned char c; 644 struct symlookup sl = { 645 .sl_name = name, 646 .sl_out = { .sym = NULL }, 647 .sl_weak_out = { .sym = NULL }, 648 .sl_elf_hash = 0, 649 .sl_gnu_hash = 5381, 650 .sl_flags = flags, 651 }; 652 653 /* Calculate both hashes in one pass */ 654 for (p = (const unsigned char *)name; (c = *p) != '\0'; p++) { 655 sl.sl_elf_hash = (sl.sl_elf_hash << 4) + c; 656 sl.sl_elf_hash ^= (sl.sl_elf_hash >> 24) & 0xf0; 657 sl.sl_gnu_hash = sl.sl_gnu_hash * 33 + c; 658 } 659 sl.sl_elf_hash &= 0x0fffffff; 660 661 if (req_obj->dyn.symbolic) 662 if (_dl_find_symbol_obj(req_obj, &sl)) 663 goto found; 664 665 if (flags & SYM_DLSYM) { 666 struct object_vector vec; 667 int i; 668 669 if (_dl_find_symbol_obj(req_obj, &sl)) 670 goto found; 671 672 /* weak definition in the specified object is good enough */ 673 if (sl.sl_weak_out.sym != NULL) 674 goto found; 675 676 /* search dlopened obj and all children */ 677 vec = req_obj->load_object->grpsym_vec; 678 for (i = 0; i < vec.len; i++) { 679 if (vec.vec[i] == req_obj) 680 continue; /* already searched */ 681 if (_dl_find_symbol_obj(vec.vec[i], &sl)) 682 goto found; 683 } 684 } else { 685 struct dep_node *n; 686 struct object_vector vec; 687 int i, skip = 0; 688 689 if ((flags & SYM_SEARCH_SELF) || (flags & SYM_SEARCH_NEXT)) 690 skip = 1; 691 692 /* 693 * search dlopened objects: global or req_obj == dlopened_obj 694 * and its children 695 */ 696 TAILQ_FOREACH(n, &_dlopened_child_list, next_sib) { 697 if (((n->data->obj_flags & DF_1_GLOBAL) == 0) && 698 (n->data != req_obj->load_object)) 699 continue; 700 701 vec = n->data->grpsym_vec; 702 for (i = 0; i < vec.len; i++) { 703 if (skip == 1) { 704 if (vec.vec[i] == req_obj) { 705 skip = 0; 706 if (flags & SYM_SEARCH_NEXT) 707 continue; 708 } else 709 continue; 710 } 711 if ((flags & SYM_SEARCH_OTHER) && 712 (vec.vec[i] == req_obj)) 713 continue; 714 if (_dl_find_symbol_obj(vec.vec[i], &sl)) 715 goto found; 716 } 717 } 718 } 719 720found: 721 if (sl.sl_out.sym == NULL) { 722 if (sl.sl_weak_out.sym != NULL) 723 sl.sl_out = sl.sl_weak_out; 724 else { 725 if ((ref_sym == NULL || 726 (ELF_ST_BIND(ref_sym->st_info) != STB_WEAK)) && 727 (flags & SYM_WARNNOTFOUND)) 728 _dl_printf("%s:%s: undefined symbol '%s'\n", 729 __progname, req_obj->load_name, name); 730 return (struct sym_res){ NULL, NULL }; 731 } 732 } 733 734 if (ref_sym != NULL && ref_sym->st_size != 0 && 735 (ref_sym->st_size != sl.sl_out.sym->st_size) && 736 (ELF_ST_TYPE(sl.sl_out.sym->st_info) != STT_FUNC) ) { 737 _dl_printf("%s:%s: %s : WARNING: " 738 "symbol(%s) size mismatch, relink your program\n", 739 __progname, req_obj->load_name, sl.sl_out.obj->load_name, 740 name); 741 } 742 743 return sl.sl_out; 744} 745 746void 747_dl_debug_state(void) 748{ 749 /* Debugger stub */ 750} 751 752/* 753 * Search for DT_SONAME, and check if this is libc 754 */ 755int 756_dl_islibc(Elf_Dyn *_dynp, Elf_Addr loff) 757{ 758 Elf_Dyn *d, *dynp = (Elf_Dyn *)((unsigned long)_dynp + loff); 759 long base = 0; 760 761 for (d = dynp; d->d_tag != DT_NULL; d++) 762 if (d->d_tag == DT_STRTAB) { 763 base = d->d_un.d_ptr + loff; 764 break; 765 } 766 if (base == 0) 767 return 0; 768 for (d = dynp; d->d_tag != DT_NULL; d++) 769 if (d->d_tag == DT_SONAME) { 770 if (_dl_strncmp((char *)(base + d->d_un.d_ptr), 771 "libc.so.", 8) == 0) 772 return 1; 773 break; 774 } 775 return 0; 776} 777 778void 779_dl_pin(int file, Elf_Phdr *phdp, void *base, size_t len, 780 void *exec_base, size_t exec_size) 781{ 782 struct pinsyscalls { 783 u_int offset; 784 u_int sysno; 785 } *syscalls; 786 int npins = 0, nsyscalls, i; 787 u_int *pins = NULL; 788 vaddr_t offset; 789 790 if (phdp->p_filesz > SYS_MAXSYSCALL * 2 * sizeof(*syscalls) || 791 phdp->p_filesz % sizeof(*syscalls) != 0 || 792 phdp->p_offset & 0x3) 793 return; 794 syscalls = _dl_mmap(NULL, phdp->p_filesz, PROT_READ, 795 MAP_PRIVATE|MAP_FILE, file, phdp->p_offset); 796 if (syscalls == MAP_FAILED) 797 return; 798 799 /* Validate, and calculate pintable size */ 800 nsyscalls = phdp->p_filesz / sizeof(*syscalls); 801 for (i = 0; i < nsyscalls; i++) { 802 if (syscalls[i].sysno < 0 || 803 syscalls[i].sysno >= SYS_MAXSYSCALL || 804 syscalls[i].offset >= len) 805 goto bad; 806 npins = MAXIMUM(npins, syscalls[i].sysno); 807 } 808 npins++; 809 810 /* 811 * Fill pintable: 0 = invalid, -1 = accept, else offset 812 * from base, rebase to text_start while at it 813 */ 814 pins = _dl_calloc(npins, sizeof(u_int)); 815 offset = exec_base - base; 816 for (i = 0; i < nsyscalls; i++) { 817 if (pins[syscalls[i].sysno]) 818 pins[syscalls[i].sysno] = (u_int)-1; /* duplicated */ 819 else 820 pins[syscalls[i].sysno] = syscalls[i].offset - offset; 821 } 822 base += offset; 823 len = len - offset; 824bad: 825 _dl_munmap(syscalls, phdp->p_filesz); 826 if (pins) 827 _dl_pinsyscalls(base, len, pins, npins); 828 _dl_free(pins); 829} 830