1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/mman.h> 28 #include <dirent.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <limits.h> 33 #include <debug.h> 34 #include <conv.h> 35 #include <elfcap.h> 36 #include "_rtld.h" 37 #include "_elf.h" 38 #include "_audit.h" 39 #include "msg.h" 40 41 /* 42 * qsort(3c) capability comparison function. 43 */ 44 static int 45 compare(const void *vp_a, const void *vp_b) 46 { 47 Fdesc *fdp_a = (Fdesc *)vp_a, *fdp_b = (Fdesc *)vp_b; 48 char *strcap_a, *strcap_b; 49 Xword hwcap_a, hwcap_b; 50 51 /* 52 * First, investigate any platform capability. 53 */ 54 strcap_a = fdp_a->fd_scapset.sc_plat; 55 strcap_b = fdp_b->fd_scapset.sc_plat; 56 57 if (strcap_a && (strcap_b == NULL)) 58 return (-1); 59 if (strcap_b && (strcap_a == NULL)) 60 return (1); 61 62 /* 63 * Second, investigate any machine capability. 64 */ 65 strcap_a = fdp_a->fd_scapset.sc_mach; 66 strcap_b = fdp_b->fd_scapset.sc_mach; 67 68 if (strcap_a && (strcap_b == NULL)) 69 return (-1); 70 if (strcap_b && (strcap_a == NULL)) 71 return (1); 72 73 /* 74 * Third, investigate any CA_SUNW_HW_2 hardware capabilities. 75 */ 76 hwcap_a = fdp_a->fd_scapset.sc_hw_2; 77 hwcap_b = fdp_b->fd_scapset.sc_hw_2; 78 79 if (hwcap_a > hwcap_b) 80 return (-1); 81 if (hwcap_a < hwcap_b) 82 return (1); 83 84 /* 85 * Finally, investigate any CA_SUNW_HW_1 hardware capabilities. 86 */ 87 hwcap_a = fdp_a->fd_scapset.sc_hw_1; 88 hwcap_b = fdp_b->fd_scapset.sc_hw_1; 89 90 if (hwcap_a > hwcap_b) 91 return (-1); 92 if (hwcap_a < hwcap_b) 93 return (1); 94 95 /* 96 * Normally, a capabilities directory contains one or more capabilities 97 * files, each with different capabilities. The role of ld.so.1 is to 98 * select the best candidate from these variants. However, we've come 99 * across cases where files containing the same capabilities have been 100 * placed in the same capabilities directory. As we can't tell which 101 * file is the best, we select neither, and diagnose this suspicious 102 * scenario. 103 */ 104 DBG_CALL(Dbg_cap_identical(fdp_a->fd_lml, fdp_a->fd_nname, 105 fdp_b->fd_nname)); 106 107 fdp_a->fd_flags |= FLG_FD_IGNORE; 108 fdp_b->fd_flags |= FLG_FD_IGNORE; 109 110 return (0); 111 } 112 113 /* 114 * Determine whether HWCAP1 capabilities value is supported. 115 */ 116 int 117 hwcap1_check(Syscapset *scapset, Xword val, Rej_desc *rej) 118 { 119 Xword mval; 120 121 /* 122 * Ensure that the kernel can cope with the required capabilities. 123 */ 124 if ((rtld_flags2 & RT_FL2_HWCAP) && 125 ((mval = (val & ~scapset->sc_hw_1)) != 0)) { 126 if (rej) { 127 static Conv_cap_val_hw1_buf_t cap_buf; 128 129 rej->rej_type = SGS_REJ_HWCAP_1; 130 rej->rej_str = conv_cap_val_hw1(mval, 131 M_MACH, 0, &cap_buf); 132 } 133 return (0); 134 } 135 return (1); 136 } 137 138 /* 139 * Determine whether HWCAP2 capabilities value is supported. 140 */ 141 int 142 hwcap2_check(Syscapset *scapset, Xword val, Rej_desc *rej) 143 { 144 Xword mval; 145 146 /* 147 * Ensure that the kernel can cope with the required capabilities. 148 */ 149 if ((mval = (val & ~scapset->sc_hw_2)) != 0) { 150 if (rej) { 151 static Conv_cap_val_hw2_buf_t cap_buf; 152 153 rej->rej_type = SGS_REJ_HWCAP_2; 154 rej->rej_str = conv_cap_val_hw2(mval, 155 M_MACH, 0, &cap_buf); 156 } 157 return (0); 158 } 159 return (1); 160 } 161 162 /* 163 * Process any software capabilities. 164 */ 165 /* ARGSUSED0 */ 166 int 167 sfcap1_check(Syscapset *scapset, Xword val, Rej_desc *rej) 168 { 169 #if defined(_ELF64) 170 /* 171 * A 64-bit executable that started the process can be restricted to a 172 * 32-bit address space. A 64-bit dependency that is restricted to a 173 * 32-bit address space can not be loaded unless the executable has 174 * established this requirement. 175 */ 176 if ((val & SF1_SUNW_ADDR32) && ((rtld_flags2 & RT_FL2_ADDR32) == 0)) { 177 if (rej) { 178 static Conv_cap_val_sf1_buf_t cap_buf; 179 180 rej->rej_type = SGS_REJ_SFCAP_1; 181 rej->rej_str = conv_cap_val_sf1(SF1_SUNW_ADDR32, 182 M_MACH, 0, &cap_buf); 183 } 184 return (0); 185 } 186 #endif 187 return (1); 188 } 189 190 /* 191 * Process any platform capability. 192 */ 193 int 194 platcap_check(Syscapset *scapset, const char *str, Rej_desc *rej) 195 { 196 /* 197 * If the platform name hasn't been set, try and obtain it. 198 */ 199 if ((scapset->sc_plat == NULL) && 200 (scapset->sc_platsz == 0)) 201 platform_name(scapset); 202 203 if ((scapset->sc_plat == NULL) || 204 (str && strcmp(scapset->sc_plat, str))) { 205 if (rej) { 206 /* 207 * Note, the platform name points to a string within an 208 * objects string table, and if that object can't be 209 * loaded, it will be unloaded and thus invalidate the 210 * string. Duplicate the string here for rejection 211 * message inheritance. 212 */ 213 rej->rej_type = SGS_REJ_PLATCAP; 214 rej->rej_str = stravl_insert(str, 0, 0, 0); 215 } 216 return (0); 217 } 218 return (1); 219 } 220 221 /* 222 * Process any machine capability. 223 */ 224 int 225 machcap_check(Syscapset *scapset, const char *str, Rej_desc *rej) 226 { 227 /* 228 * If the machine name hasn't been set, try and obtain it. 229 */ 230 if ((scapset->sc_mach == NULL) && 231 (scapset->sc_machsz == 0)) 232 machine_name(scapset); 233 234 if ((scapset->sc_mach == NULL) || 235 (str && strcmp(scapset->sc_mach, str))) { 236 if (rej) { 237 /* 238 * Note, the machine name points to a string within an 239 * objects string table, and if that object can't be 240 * loaded, it will be unloaded and thus invalidate the 241 * string. Duplicate the string here for rejection 242 * message inheritance. 243 */ 244 rej->rej_type = SGS_REJ_MACHCAP; 245 rej->rej_str = stravl_insert(str, 0, 0, 0); 246 } 247 return (0); 248 } 249 return (1); 250 } 251 252 /* 253 * Generic front-end to capabilities validation. 254 */ 255 static int 256 cap_check(Cap *cptr, char *strs, int alt, Fdesc *fdp, Rej_desc *rej) 257 { 258 Syscapset *scapset; 259 int totplat, ivlplat, totmach, ivlmach; 260 261 /* 262 * If the caller has no capabilities, then the object is valid. 263 */ 264 if (cptr == NULL) 265 return (1); 266 267 if (alt) 268 scapset = alt_scapset; 269 else 270 scapset = org_scapset; 271 272 totplat = ivlplat = totmach = ivlmach = 0; 273 274 while (cptr->c_tag != CA_SUNW_NULL) { 275 Xword val = cptr->c_un.c_val; 276 char *str; 277 278 switch (cptr->c_tag) { 279 case CA_SUNW_HW_1: 280 /* 281 * Remove any historic values that should not be 282 * involved with any validation. 283 */ 284 val &= ~AV_HW1_IGNORE; 285 286 if (hwcap1_check(scapset, val, rej) == 0) 287 return (0); 288 if (fdp) 289 fdp->fd_scapset.sc_hw_1 = val; 290 break; 291 case CA_SUNW_SF_1: 292 if (sfcap1_check(scapset, val, rej) == 0) 293 return (0); 294 if (fdp) 295 fdp->fd_scapset.sc_sf_1 = val; 296 break; 297 case CA_SUNW_HW_2: 298 if (hwcap2_check(scapset, val, rej) == 0) 299 return (0); 300 if (fdp) 301 fdp->fd_scapset.sc_hw_2 = val; 302 break; 303 case CA_SUNW_PLAT: 304 /* 305 * A capabilities group can define multiple platform 306 * names that are appropriate. Only if all the names 307 * are deemed invalid is the group determined 308 * inappropriate. 309 */ 310 if (totplat == ivlplat) { 311 totplat++; 312 313 str = strs + val; 314 315 if (platcap_check(scapset, str, rej) == 0) 316 ivlplat++; 317 else if (fdp) 318 fdp->fd_scapset.sc_plat = str; 319 } 320 break; 321 case CA_SUNW_MACH: 322 /* 323 * A capabilities group can define multiple machine 324 * names that are appropriate. Only if all the names 325 * are deemed invalid is the group determined 326 * inappropriate. 327 */ 328 if (totmach == ivlmach) { 329 totmach++; 330 331 str = strs + val; 332 333 if (machcap_check(scapset, str, rej) == 0) 334 ivlmach++; 335 else if (fdp) 336 fdp->fd_scapset.sc_mach = str; 337 } 338 break; 339 case CA_SUNW_ID: 340 /* 341 * Capabilities identifiers provide for diagnostics, 342 * but are not attributes that must be compared with 343 * the system. They are ignored. 344 */ 345 break; 346 default: 347 rej->rej_type = SGS_REJ_UNKCAP; 348 rej->rej_info = cptr->c_tag; 349 return (0); 350 } 351 cptr++; 352 } 353 354 /* 355 * If any platform names, or machine names were found, and all were 356 * invalid, indicate that the object is inappropriate. 357 */ 358 if ((totplat && (totplat == ivlplat)) || 359 (totmach && (totmach == ivlmach))) 360 return (0); 361 362 return (1); 363 } 364 365 #define HWAVL_RECORDED(n) pnavl_recorded(&capavl, n, NULL, NULL) 366 367 /* 368 * Determine whether a link-map should use alternative system capabilities. 369 */ 370 static void 371 cap_check_lmp_init(Rt_map *lmp) 372 { 373 int alt = 0; 374 375 /* 376 * If an alternative set of system capabilities have been established, 377 * and only specific files should use these alternative system 378 * capabilities, determine whether this file is one of those specified. 379 */ 380 if (capavl) { 381 const char *file; 382 383 /* 384 * The simplest way to reference a file is to use its file name 385 * (soname), however try all of the names that this file is 386 * known by. 387 */ 388 if ((file = strrchr(NAME(lmp), '/')) != NULL) 389 file++; 390 else 391 file = NULL; 392 393 if ((file && (HWAVL_RECORDED(file) != 0)) || 394 (HWAVL_RECORDED(NAME(lmp)) != 0) || 395 ((PATHNAME(lmp) != NAME(lmp)) && 396 (HWAVL_RECORDED(PATHNAME(lmp)) != 0))) 397 alt = 1; 398 399 if (alt == 0) { 400 Aliste idx; 401 const char *cp; 402 403 for (APLIST_TRAVERSE(ALIAS(lmp), idx, cp)) { 404 if ((alt = HWAVL_RECORDED(cp)) != 0) 405 break; 406 } 407 } 408 } 409 410 /* 411 * Indicate if this link-map should use alternative system capabilities, 412 * and that the alternative system capabilities check has been carried 413 * out. 414 */ 415 if ((org_scapset != alt_scapset) && ((capavl == NULL) || alt)) 416 FLAGS1(lmp) |= FL1_RT_ALTCAP; 417 FLAGS1(lmp) |= FL1_RT_ALTCHECK; 418 } 419 420 /* 421 * Validate the capabilities requirements of a link-map. 422 * 423 * This routine is called for main, where a link-map is constructed from the 424 * mappings returned from exec(), and for any symbol capabilities comparisons. 425 */ 426 int 427 cap_check_lmp(Rt_map *lmp, Rej_desc *rej) 428 { 429 if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0) 430 cap_check_lmp_init(lmp); 431 432 return (cap_check(CAP(lmp), STRTAB(lmp), 433 (FLAGS1(lmp) & FL1_RT_ALTCAP), NULL, rej)); 434 } 435 436 /* 437 * Validate the capabilities requirements of a file under inspection. 438 * This file is still under the early stages of loading, and has no link-map 439 * yet. The file must have an object capabilities definition (PT_SUNWCAP), to 440 * have gotten us here. The logic here is the same as cap_check_lmp(). 441 */ 442 int 443 cap_check_fdesc(Fdesc *fdp, Cap *cptr, char *strs, Rej_desc *rej) 444 { 445 int alt = 0; 446 447 /* 448 * If an alternative set of system capabilities have been established, 449 * and only specific files should use these alternative system 450 * capabilities, determine whether this file is one of those specified. 451 */ 452 if (capavl) { 453 const char *file; 454 455 /* 456 * The simplest way to reference a file is to use its file name 457 * (soname), however try all of the names that this file is 458 * known by. 459 */ 460 if (fdp->fd_oname && 461 ((file = strrchr(fdp->fd_oname, '/')) != NULL)) 462 file++; 463 else 464 file = NULL; 465 466 if ((file && (HWAVL_RECORDED(file) != 0)) || 467 (fdp->fd_oname && (HWAVL_RECORDED(fdp->fd_oname) != 0)) || 468 (fdp->fd_nname && (HWAVL_RECORDED(fdp->fd_nname) != 0)) || 469 (fdp->fd_pname && (fdp->fd_pname != fdp->fd_nname) && 470 (HWAVL_RECORDED(fdp->fd_pname) != 0))) 471 alt = 1; 472 } 473 474 /* 475 * Indicate if this file descriptor should use alternative system 476 * capabilities, and that the alternative system capabilities check has 477 * been carried out. 478 */ 479 if ((org_scapset != alt_scapset) && ((capavl == NULL) || alt)) 480 fdp->fd_flags |= FLG_FD_ALTCAP; 481 fdp->fd_flags |= FLG_FD_ALTCHECK; 482 483 /* 484 * Verify that the required capabilities are supported by the reference. 485 */ 486 return (cap_check(cptr, strs, (fdp->fd_flags & FLG_FD_ALTCAP), 487 fdp, rej)); 488 } 489 490 /* 491 * Free a file descriptor list. As part of building this list, the original 492 * names for each capabilities candidate were duplicated for use in later 493 * diagnostics. These names need to be freed. 494 */ 495 void 496 free_fd(Alist *fdalp) 497 { 498 if (fdalp) { 499 Aliste idx; 500 Fdesc *fdp; 501 502 for (ALIST_TRAVERSE(fdalp, idx, fdp)) { 503 if (fdp->fd_oname) 504 free((void *)fdp->fd_oname); 505 } 506 free(fdalp); 507 } 508 } 509 510 /* 511 * When $CAPABILITY (or $HWCAP) is used to represent dependencies, take the 512 * associated directory and analyze all the files it contains. 513 */ 514 static int 515 cap_dir(Alist **fdalpp, Lm_list *lml, const char *dname, Rt_map *clmp, 516 uint_t flags, Rej_desc *rej, int *in_nfavl) 517 { 518 char path[PATH_MAX], *dst; 519 const char *src; 520 DIR *dir; 521 struct dirent *dirent; 522 Alist *fdalp = NULL; 523 Aliste idx; 524 Fdesc *fdp; 525 int error = 0; 526 527 /* 528 * Access the directory in preparation for reading its entries. If 529 * successful, establish the initial pathname. 530 */ 531 if ((dir = opendir(dname)) == NULL) { 532 Rej_desc _rej = { 0 }; 533 534 _rej.rej_type = SGS_REJ_STR; 535 _rej.rej_name = dname; 536 _rej.rej_str = strerror(errno); 537 DBG_CALL(Dbg_file_rejected(lml, &_rej, M_MACH)); 538 rejection_inherit(rej, &_rej); 539 return (0); 540 } 541 542 for (dst = path, src = dname; *src; dst++, src++) 543 *dst = *src; 544 *dst++ = '/'; 545 546 /* 547 * Read each entry from the directory and determine whether it is a 548 * valid ELF file. 549 */ 550 while ((dirent = readdir(dir)) != NULL) { 551 const char *file = dirent->d_name; 552 char *_dst; 553 Fdesc fd = { 0 }; 554 Rej_desc _rej = { 0 }; 555 Pdesc pd = { 0 }; 556 557 /* 558 * Ignore "." and ".." entries. 559 */ 560 if ((file[0] == '.') && ((file[1] == '\0') || 561 ((file[1] == '.') && (file[2] == '\0')))) 562 continue; 563 564 /* 565 * Complete the full pathname. 566 */ 567 for (_dst = dst, src = file, file = dst; *src; _dst++, src++) 568 *_dst = *src; 569 *_dst = '\0'; 570 571 /* 572 * Trace the inspection of this file, and determine any 573 * auditor substitution. 574 */ 575 pd.pd_pname = path; 576 pd.pd_flags = PD_FLG_PNSLASH; 577 578 if (load_trace(lml, &pd, clmp, &fd) == NULL) 579 continue; 580 581 /* 582 * Note, all directory entries are processed by find_path(), 583 * even entries that are directories themselves. This single 584 * point for control keeps the number of stat()'s down, and 585 * provides a single point for error diagnostics. 586 */ 587 if (find_path(lml, clmp, flags, &fd, &_rej, in_nfavl) == 0) { 588 rejection_inherit(rej, &_rej); 589 continue; 590 } 591 592 DBG_CALL(Dbg_cap_candidate(lml, fd.fd_nname)); 593 594 /* 595 * If this object has already been loaded, save the capabilities 596 * for later sorting. Otherwise we have a new candidate. 597 */ 598 if (fd.fd_lmp) 599 fd.fd_scapset = CAPSET(fd.fd_lmp); 600 fd.fd_lml = lml; 601 602 /* 603 * Duplicate the original name, as this may be required for 604 * later diagnostics. Keep a copy of the file descriptor for 605 * analysis once all capabilities candidates have been 606 * determined. 607 */ 608 if (((fd.fd_oname = strdup(fd.fd_oname)) == NULL) || 609 (alist_append(&fdalp, &fd, sizeof (Fdesc), 610 AL_CNT_CAP) == NULL)) { 611 error = 1; 612 break; 613 } 614 } 615 (void) closedir(dir); 616 617 /* 618 * If no objects have been found, we're done. Also, if an allocation 619 * error occurred while processing any object, remove any objects that 620 * had already been added to the list and return. 621 */ 622 if ((fdalp == NULL) || error) { 623 if (fdalp) 624 free_fd(fdalp); 625 return (0); 626 } 627 628 /* 629 * Having processed and retained all candidates from this directory, 630 * sort them, based on the precedence of their hardware capabilities. 631 */ 632 qsort(fdalp->al_data, fdalp->al_nitems, fdalp->al_size, compare); 633 634 /* 635 * If any objects were found to have the same capabilities, then these 636 * objects must be rejected, as we can't tell which object is more 637 * appropriate. 638 */ 639 for (ALIST_TRAVERSE(fdalp, idx, fdp)) { 640 if (fdp->fd_flags & FLG_FD_IGNORE) 641 alist_delete(fdalp, &idx); 642 } 643 644 if (fdalp->al_nitems == 0) { 645 free_fd(fdalp); 646 return (0); 647 } 648 649 *fdalpp = fdalp; 650 return (1); 651 } 652 653 int 654 cap_filtees(Alist **alpp, Aliste oidx, const char *dir, Aliste nlmco, 655 Rt_map *flmp, Rt_map *clmp, const char *ref, int mode, uint_t flags, 656 int *in_nfavl) 657 { 658 Alist *fdalp = NULL; 659 Aliste idx; 660 Fdesc *fdp; 661 Lm_list *lml = LIST(flmp); 662 int unused = 0; 663 Rej_desc rej = { 0 }; 664 665 if (cap_dir(&fdalp, lml, dir, flmp, flags, &rej, in_nfavl) == 0) 666 return (0); 667 668 /* 669 * Now complete the mapping of each of the ordered objects, adding 670 * each object to a new pathname descriptor. 671 */ 672 for (ALIST_TRAVERSE(fdalp, idx, fdp)) { 673 Rt_map *nlmp; 674 Grp_hdl *ghp = NULL; 675 Pdesc *pdp; 676 int audit = 0; 677 678 if (unused) 679 continue; 680 681 /* 682 * Complete mapping the file, obtaining a handle, and continue 683 * to analyze the object, establishing dependencies and 684 * relocating. Remove the file descriptor at this point, as it 685 * is no longer required. 686 */ 687 DBG_CALL(Dbg_file_filtee(lml, NAME(flmp), fdp->fd_nname, 0)); 688 689 nlmp = load_path(lml, nlmco, flmp, mode, 690 (flags | FLG_RT_PUBHDL), &ghp, fdp, &rej, in_nfavl); 691 if (nlmp == NULL) 692 continue; 693 694 /* 695 * Create a new pathname descriptor to represent this filtee, 696 * and insert this descriptor in the Alist following the 697 * hardware descriptor that seeded this processing. 698 */ 699 if ((pdp = alist_insert(alpp, 0, sizeof (Pdesc), 700 AL_CNT_FILTEES, ++oidx)) == NULL) { 701 if (ghp) 702 remove_lmc(lml, flmp, nlmco, NAME(nlmp)); 703 return (0); 704 } 705 706 pdp->pd_pname = NAME(nlmp); 707 pdp->pd_plen = strlen(NAME(nlmp)); 708 709 /* 710 * Establish the filter handle to prevent any recursion. 711 */ 712 if (nlmp && ghp) { 713 ghp->gh_flags |= GPH_FILTEE; 714 pdp->pd_info = (void *)ghp; 715 } 716 717 /* 718 * Audit the filter/filtee established. A return of 0 719 * indicates the auditor wishes to ignore this filtee. 720 */ 721 if (nlmp && (lml->lm_tflags | FLAGS1(flmp)) & 722 LML_TFLG_AUD_OBJFILTER) { 723 if (audit_objfilter(flmp, ref, nlmp, 0) == 0) { 724 audit = 1; 725 nlmp = NULL; 726 } 727 } 728 729 /* 730 * Finish processing the objects associated with this request. 731 */ 732 if (nlmp && ghp && (((nlmp = analyze_lmc(lml, nlmco, nlmp, 733 clmp, in_nfavl)) == NULL) || 734 (relocate_lmc(lml, nlmco, flmp, nlmp, in_nfavl) == 0))) 735 nlmp = NULL; 736 737 /* 738 * If the filtee has been successfully processed, then create 739 * an association between the filter and the filtee. This 740 * association provides sufficient information to tear down the 741 * filter and filtee if necessary. 742 */ 743 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); 744 if (nlmp && ghp && 745 (hdl_add(ghp, flmp, GPD_FILTER, NULL) == NULL)) 746 nlmp = NULL; 747 748 /* 749 * If this object is marked an end-filtee, we're done. 750 */ 751 if (nlmp && ghp && (FLAGS1(nlmp) & FL1_RT_ENDFILTE)) 752 unused = 1; 753 754 /* 755 * If this filtee loading has failed, generate a diagnostic. 756 * Null out the path name descriptor entry, and continue the 757 * search. 758 */ 759 if (nlmp == NULL) { 760 DBG_CALL(Dbg_file_filtee(lml, 0, pdp->pd_pname, audit)); 761 762 /* 763 * If attempting to load this filtee required a new 764 * link-map control list to which this request has 765 * added objects, then remove all the objects that 766 * have been associated to this request. 767 */ 768 if (nlmco != ALIST_OFF_DATA) 769 remove_lmc(lml, flmp, nlmco, pdp->pd_pname); 770 771 pdp->pd_plen = 0; 772 pdp->pd_info = NULL; 773 } 774 } 775 776 free_fd(fdalp); 777 return (1); 778 } 779 780 /* 781 * Load an individual capabilities object. 782 */ 783 Rt_map * 784 load_cap(Lm_list *lml, Aliste lmco, const char *dir, Rt_map *clmp, 785 uint_t mode, uint_t flags, Grp_hdl **hdl, Rej_desc *rej, int *in_nfavl) 786 { 787 Alist *fdalp = NULL; 788 Aliste idx; 789 Fdesc *fdp; 790 int found = 0; 791 Rt_map *lmp = NULL; 792 793 /* 794 * Obtain the sorted list of hardware capabilities objects available. 795 */ 796 if (cap_dir(&fdalp, lml, dir, clmp, flags, rej, in_nfavl) == 0) 797 return (NULL); 798 799 /* 800 * From the list of hardware capability objects, use the first and 801 * discard the rest. 802 */ 803 for (ALIST_TRAVERSE(fdalp, idx, fdp)) { 804 Fdesc fd = *fdp; 805 806 if ((found == 0) && ((lmp = load_path(lml, lmco, clmp, mode, 807 flags, hdl, &fd, rej, in_nfavl)) != NULL)) 808 found++; 809 } 810 811 free_fd(fdalp); 812 return (lmp); 813 } 814 815 /* 816 * Use a case insensitive string match when looking up capability mask 817 * values by name, and omit the AV_ prefix. 818 */ 819 #define ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP 820 821 /* 822 * To aid in the development and testing of capabilities, an alternative system 823 * capabilities group can be specified. This alternative set is initialized 824 * from the system capabilities that are normally used to validate all object 825 * loading. However, the user can disable, enable or override flags within 826 * this alternative set, and thus affect object loading. 827 * 828 * This technique is usually combined with defining the family of objects 829 * that should be compared against this alternative set. Without defining the 830 * family of objects, all objects loaded by ld.so.1 are validated against the 831 * alternative set. This can prevent the loading of critical system objects 832 * like libc, and thus prevent process execution. 833 */ 834 typedef enum { 835 CAP_OVERRIDE = 0, /* override existing capabilities */ 836 CAP_ENABLE = 1, /* enable capabilities */ 837 CAP_DISABLE = 2 /* disable capabilities */ 838 } cap_mode; 839 840 static struct { 841 elfcap_mask_t cs_val[3]; /* value settings, and indicator for */ 842 int cs_set[3]; /* OVERRIDE, ENABLE and DISABLE */ 843 elfcap_mask_t *cs_aval; /* alternative variable for final */ 844 /* update */ 845 } cap_settings[3] = { 846 { { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_HW_1 */ 847 { { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_SF_1 */ 848 { { 0, 0, 0 }, { 0, 0, 0 }, NULL } /* CA_SUNW_HW_2 */ 849 }; 850 851 static int 852 cap_modify(Xword tag, const char *str) 853 { 854 char *caps, *ptr, *next; 855 cap_mode mode = CAP_OVERRIDE; 856 Xword ndx; 857 858 if ((caps = strdup(str)) == NULL) 859 return (0); 860 861 ptr = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next); 862 do { 863 Xword val = 0; 864 865 /* 866 * Determine whether this token should be enabled (+), 867 * disabled (-), or override any existing settings. 868 */ 869 if (*ptr == '+') { 870 mode = CAP_ENABLE; 871 ptr++; 872 } else if (*ptr == '-') { 873 mode = CAP_DISABLE; 874 ptr++; 875 } 876 877 /* 878 * Process the capabilities as directed by the calling tag. 879 */ 880 switch (tag) { 881 case CA_SUNW_HW_1: 882 /* 883 * Determine whether the capabilities string matches 884 * a known hardware capability mask. Note, the caller 885 * indicates that these are hardware capabilities by 886 * passing in the CA_SUNW_HW_1 tag. However, the 887 * tokens could be CA_SUNW_HW_1 or CA_SUNW_HW_2. 888 */ 889 if ((val = (Xword)elfcap_hw2_from_str(ELFCAP_STYLE, 890 ptr, M_MACH)) != 0) { 891 ndx = CA_SUNW_HW_2; 892 break; 893 } 894 if ((val = (Xword)elfcap_hw1_from_str(ELFCAP_STYLE, 895 ptr, M_MACH)) != 0) 896 ndx = CA_SUNW_HW_1; 897 break; 898 case CA_SUNW_SF_1: 899 /* 900 * Determine whether the capabilities string matches a 901 * known software capability mask. Note, the callers 902 * indication of what capabilities to process are 903 * triggered by a tag of CA_SUNW_SF_1, but the tokens 904 * processed could be CA_SUNW_SF_1, CA_SUNW_SF_2, etc. 905 */ 906 if ((val = (Xword)elfcap_sf1_from_str(ELFCAP_STYLE, 907 ptr, M_MACH)) != 0) 908 ndx = CA_SUNW_SF_1; 909 break; 910 } 911 912 /* 913 * If a capabilities token has not been matched, interpret the 914 * string as a number. To provide for setting the various 915 * families (CA_SUNW_HW_1, CA_SUNW_HW_2), the number can be 916 * prefixed with the (bracketed) family index. 917 * 918 * LD_HWCAP=[1]0x40 sets CA_SUNW_HW_1 with 0x40 919 * LD_HWCAP=[2]0x80 sets CA_SUNW_HW_2 with 0x80 920 * 921 * Invalid indexes are ignored. 922 */ 923 if (val == 0) { 924 if ((*ptr == '[') && (*(ptr + 2) == ']')) { 925 if (*(ptr + 1) == '1') { 926 ndx = tag; 927 ptr += 3; 928 } else if (*(ptr + 1) == '2') { 929 if (tag == CA_SUNW_HW_1) { 930 ndx = CA_SUNW_HW_2; 931 ptr += 3; 932 } else { 933 /* invalid index */ 934 continue; 935 } 936 } else { 937 /* invalid index */ 938 continue; 939 } 940 } else 941 ndx = tag; 942 943 errno = 0; 944 if (((val = strtol(ptr, NULL, 16)) == 0) && errno) 945 continue; 946 } 947 cap_settings[ndx - 1].cs_val[mode] |= val; 948 cap_settings[ndx - 1].cs_set[mode]++; 949 950 } while ((ptr = strtok_r(NULL, 951 MSG_ORIG(MSG_CAP_DELIMIT), &next)) != NULL); 952 953 /* 954 * If the "override" token was supplied, set the alternative 955 * system capabilities, then enable or disable others. 956 */ 957 for (ndx = 0; ndx < CA_SUNW_HW_2; ndx++) { 958 if (cap_settings[ndx].cs_set[CAP_OVERRIDE]) 959 *(cap_settings[ndx].cs_aval) = 960 cap_settings[ndx].cs_val[CAP_OVERRIDE]; 961 if (cap_settings[ndx].cs_set[CAP_ENABLE]) 962 *(cap_settings[ndx].cs_aval) |= 963 cap_settings[ndx].cs_val[CAP_ENABLE]; 964 if (cap_settings[ndx].cs_set[CAP_DISABLE]) 965 *(cap_settings[ndx].cs_aval) &= 966 ~cap_settings[ndx].cs_val[CAP_DISABLE]; 967 } 968 free(caps); 969 return (1); 970 } 971 #undef ELFCAP_STYLE 972 973 /* 974 * Create an AVL tree of objects that are to be validated against an alternative 975 * system capabilities value. 976 */ 977 static int 978 cap_files(const char *str) 979 { 980 char *caps, *name, *next; 981 982 if ((caps = strdup(str)) == NULL) 983 return (0); 984 985 name = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next); 986 do { 987 avl_index_t where; 988 PathNode *pnp; 989 uint_t hash = sgs_str_hash(name); 990 991 /* 992 * Determine whether this pathname has already been recorded. 993 */ 994 if (pnavl_recorded(&capavl, name, hash, &where)) 995 continue; 996 997 if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) { 998 pnp->pn_name = name; 999 pnp->pn_hash = hash; 1000 avl_insert(capavl, pnp, where); 1001 } 1002 } while ((name = strtok_r(NULL, 1003 MSG_ORIG(MSG_CAP_DELIMIT), &next)) != NULL); 1004 1005 return (1); 1006 } 1007 1008 /* 1009 * Set alternative system capabilities. A user can establish alternative system 1010 * capabilities from the environment, or from a configuration file. This 1011 * routine is called in each instance. Environment variables only set the 1012 * replaceable (rpl) variables. Configuration files can set both replaceable 1013 * (rpl) and permanent (prm) variables. 1014 */ 1015 int 1016 cap_alternative(void) 1017 { 1018 /* 1019 * If no capabilities have been set, we're done. 1020 */ 1021 if ((rpl_hwcap == NULL) && (rpl_sfcap == NULL) && 1022 (rpl_machcap == NULL) && (rpl_platcap == NULL) && 1023 (prm_hwcap == NULL) && (prm_sfcap == NULL) && 1024 (prm_machcap == NULL) && (prm_platcap == NULL)) 1025 return (1); 1026 1027 /* 1028 * If the user has requested to modify any capabilities, establish a 1029 * unique set from the present system capabilities. 1030 */ 1031 if ((alt_scapset = malloc(sizeof (Syscapset))) == NULL) 1032 return (0); 1033 *alt_scapset = *org_scapset; 1034 1035 cap_settings[CA_SUNW_HW_1 - 1].cs_aval = &alt_scapset->sc_hw_1; 1036 cap_settings[CA_SUNW_SF_1 - 1].cs_aval = &alt_scapset->sc_sf_1; 1037 cap_settings[CA_SUNW_HW_2 - 1].cs_aval = &alt_scapset->sc_hw_2; 1038 1039 /* 1040 * Process any replaceable variables. 1041 */ 1042 if (rpl_hwcap && (cap_modify(CA_SUNW_HW_1, rpl_hwcap) == 0)) 1043 return (0); 1044 if (rpl_sfcap && (cap_modify(CA_SUNW_SF_1, rpl_sfcap) == 0)) 1045 return (0); 1046 1047 if (rpl_platcap) { 1048 alt_scapset->sc_plat = (char *)rpl_platcap; 1049 alt_scapset->sc_platsz = strlen(rpl_platcap); 1050 } 1051 if (rpl_machcap) { 1052 alt_scapset->sc_mach = (char *)rpl_machcap; 1053 alt_scapset->sc_machsz = strlen(rpl_machcap); 1054 } 1055 1056 if (rpl_cap_files && (cap_files(rpl_cap_files) == 0)) 1057 return (0); 1058 1059 /* 1060 * Process any permanent variables. 1061 */ 1062 if (prm_hwcap && (cap_modify(CA_SUNW_HW_1, prm_hwcap) == 0)) 1063 return (0); 1064 if (prm_sfcap && (cap_modify(CA_SUNW_SF_1, prm_sfcap) == 0)) 1065 return (0); 1066 1067 if (prm_platcap) { 1068 alt_scapset->sc_plat = (char *)prm_platcap; 1069 alt_scapset->sc_platsz = strlen(prm_platcap); 1070 } 1071 if (prm_machcap) { 1072 alt_scapset->sc_mach = (char *)prm_machcap; 1073 alt_scapset->sc_machsz = strlen(prm_machcap); 1074 } 1075 1076 if (prm_cap_files && (cap_files(prm_cap_files) == 0)) 1077 return (0); 1078 1079 /* 1080 * Reset the replaceable variables. If this is the environment variable 1081 * processing, these variables are now available for configuration file 1082 * initialization. 1083 */ 1084 rpl_hwcap = rpl_sfcap = rpl_machcap = rpl_platcap = 1085 rpl_cap_files = NULL; 1086 1087 return (1); 1088 } 1089 1090 /* 1091 * Take the index from a Capinfo entry and determine the associated capabilities 1092 * set. Verify that the capabilities are available for this system. 1093 */ 1094 static int 1095 sym_cap_check(Cap *cptr, uint_t cndx, Syscapset *bestcapset, Rt_map *lmp, 1096 const char *name, uint_t ndx) 1097 { 1098 Syscapset *scapset; 1099 int totplat, ivlplat, totmach, ivlmach, capfail = 0; 1100 1101 /* 1102 * Determine whether this file requires validation against alternative 1103 * system capabilities. 1104 */ 1105 if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0) 1106 cap_check_lmp_init(lmp); 1107 1108 if (FLAGS1(lmp) & FL1_RT_ALTCAP) 1109 scapset = alt_scapset; 1110 else 1111 scapset = org_scapset; 1112 1113 totplat = ivlplat = totmach = ivlmach = 0; 1114 1115 /* 1116 * A capabilities index points to a capabilities group that can consist 1117 * of one or more capabilities, terminated with a CA_SUNW_NULL entry. 1118 */ 1119 for (cptr += cndx; cptr->c_tag != CA_SUNW_NULL; cptr++) { 1120 Xword val = cptr->c_un.c_val; 1121 char *str; 1122 1123 switch (cptr->c_tag) { 1124 case CA_SUNW_HW_1: 1125 /* 1126 * Remove any historic values that should not be 1127 * involved with any validation. 1128 */ 1129 val &= ~AV_HW1_IGNORE; 1130 1131 bestcapset->sc_hw_1 = val; 1132 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_1, 1133 name, ndx, M_MACH, bestcapset)); 1134 1135 if (hwcap1_check(scapset, val, NULL) == 0) 1136 capfail++; 1137 break; 1138 case CA_SUNW_SF_1: 1139 bestcapset->sc_sf_1 = val; 1140 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_SF_1, 1141 name, ndx, M_MACH, bestcapset)); 1142 1143 if (sfcap1_check(scapset, val, NULL) == 0) 1144 capfail++; 1145 break; 1146 case CA_SUNW_HW_2: 1147 bestcapset->sc_hw_2 = val; 1148 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_2, 1149 name, ndx, M_MACH, bestcapset)); 1150 1151 if (hwcap2_check(scapset, val, NULL) == 0) 1152 capfail++; 1153 break; 1154 case CA_SUNW_PLAT: 1155 /* 1156 * A capabilities set can define multiple platform names 1157 * that are appropriate. Only if all the names are 1158 * deemed invalid is the group determined inappropriate. 1159 */ 1160 if (totplat == ivlplat) { 1161 totplat++; 1162 1163 str = STRTAB(lmp) + val; 1164 bestcapset->sc_plat = str; 1165 1166 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_PLAT, 1167 name, ndx, M_MACH, bestcapset)); 1168 1169 if (platcap_check(scapset, str, NULL) == 0) 1170 ivlplat++; 1171 } 1172 break; 1173 case CA_SUNW_MACH: 1174 /* 1175 * A capabilities set can define multiple machine names 1176 * that are appropriate. Only if all the names are 1177 * deemed invalid is the group determined inappropriate. 1178 */ 1179 if (totmach == ivlmach) { 1180 totmach++; 1181 1182 str = STRTAB(lmp) + val; 1183 bestcapset->sc_mach = str; 1184 1185 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_MACH, 1186 name, ndx, M_MACH, bestcapset)); 1187 1188 if (machcap_check(scapset, str, NULL) == 0) 1189 ivlmach++; 1190 } 1191 break; 1192 default: 1193 break; 1194 } 1195 } 1196 1197 /* 1198 * If any platform definitions, or machine definitions were found, and 1199 * all were invalid, indicate that the object is inappropriate. 1200 */ 1201 if (capfail || (totplat && (totplat == ivlplat)) || 1202 (totmach && (totmach == ivlmach))) { 1203 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_REJECTED, name, ndx, 1204 M_MACH, NULL)); 1205 return (0); 1206 } 1207 1208 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_CANDIDATE, name, ndx, 1209 M_MACH, NULL)); 1210 return (1); 1211 } 1212 1213 /* 1214 * Determine whether a symbols capabilities are more significant than any that 1215 * have already been validated. The precedence of capabilities are: 1216 * 1217 * PLATCAP -> MACHCAP -> HWCAP_2 -> HWCAP_1 1218 * 1219 * 1220 * Presently we make no comparisons of software capabilities. However, should 1221 * this symbol capability have required the SF1_SUNW_ADDR32 attribute, then 1222 * this would have been validated as appropriate or not. 1223 * 1224 * bestcapset is the presently available 'best' capabilities group, and 1225 * symcapset is the present capabilities group under investigation. Return 0 1226 * if the bestcapset should remain in affect, or 1 if the symcapset is better. 1227 */ 1228 inline static int 1229 is_sym_the_best(Syscapset *bestcapset, Syscapset *symcapset) 1230 { 1231 /* 1232 * Check any platform capability. If the new symbol isn't associated 1233 * with a CA_SUNW_PLAT capability, and the best symbol is, then retain 1234 * the best capabilities group. If the new symbol is associated with a 1235 * CA_SUNW_PLAT capability, and the best symbol isn't, then the new 1236 * symbol needs to be taken. 1237 */ 1238 if (bestcapset->sc_plat && (symcapset->sc_plat == NULL)) 1239 return (0); 1240 1241 if ((bestcapset->sc_plat == NULL) && symcapset->sc_plat) 1242 return (1); 1243 1244 /* 1245 * Check any machine name capability. If the new symbol isn't 1246 * associated with a CA_SUNW_MACH capability, and the best symbol is, 1247 * then retain the best capabilities group. If the new symbol is 1248 * associated with a CA_SUNW_MACH capability, and the best symbol isn't, 1249 * then the new symbol needs to be taken. 1250 */ 1251 if (bestcapset->sc_mach && (symcapset->sc_mach == NULL)) 1252 return (0); 1253 1254 if ((bestcapset->sc_mach == NULL) && symcapset->sc_mach) 1255 return (1); 1256 1257 /* 1258 * Check the hardware capabilities. If the best symbols CA_SUNW_HW_2 1259 * capabilities are greater than the new symbols capabilities, then 1260 * retain the best capabilities group. If the new symbols CA_SUNW_HW_2 1261 * capabilities are greater than the best symbol, then the new symbol 1262 * needs to be taken. 1263 */ 1264 if (bestcapset->sc_hw_2 > symcapset->sc_hw_2) 1265 return (0); 1266 1267 if (bestcapset->sc_hw_2 < symcapset->sc_hw_2) 1268 return (1); 1269 1270 /* 1271 * Check the remaining hardware capabilities. If the best symbols 1272 * CA_SUNW_HW_1 capabilities are greater than the new symbols 1273 * capabilities, then retain the best capabilities group. If the new 1274 * symbols CA_SUNW_HW_1 capabilities are greater than the best symbol, 1275 * then the new symbol needs to be taken. 1276 */ 1277 if (bestcapset->sc_hw_1 > symcapset->sc_hw_1) 1278 return (0); 1279 1280 if (bestcapset->sc_hw_1 < symcapset->sc_hw_1) 1281 return (1); 1282 1283 /* 1284 * Both capabilities are the same. Retain the best on a first-come 1285 * first-served basis. 1286 */ 1287 return (0); 1288 } 1289 1290 /* 1291 * Initiate symbol capabilities processing. If an initial symbol lookup 1292 * results in binding to a symbol that has an associated SUNW_capinfo entry, 1293 * we arrive here. 1294 * 1295 * The standard model is that this initial symbol is the lead capabilities 1296 * symbol (defined as CAPINFO_SUNW_GLOB) of a capabilities family. This lead 1297 * symbol's SUNW_capinfo information points to the SUNW_capchain entry that 1298 * provides the family symbol indexes. We traverse this chain, looking at 1299 * each family member, to discover the best capabilities instance. This 1300 * instance name and symbol information is returned to establish the final 1301 * symbol binding. 1302 * 1303 * If the symbol that got us here is not CAPINFO_SUNW_GLOB, then we've bound 1304 * directly to a capabilities symbol which must be verified. This is not the 1305 * model created by ld(1) using -z symbolcap, but might be created directly 1306 * within a relocatable object by the compilation system. 1307 */ 1308 int 1309 cap_match(Sresult *srp, uint_t symndx, Sym *symtabptr, char *strtabptr) 1310 { 1311 Rt_map *ilmp = srp->sr_dmap; 1312 Sym *bsym = NULL; 1313 const char *bname; 1314 Syscapset bestcapset = { 0 }; 1315 Cap *cap; 1316 Capchain *capchain; 1317 uchar_t grpndx; 1318 uint_t ochainndx, nchainndx, bndx; 1319 1320 cap = CAP(ilmp); 1321 capchain = CAPCHAIN(ilmp); 1322 1323 grpndx = (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx]); 1324 1325 /* 1326 * If this symbols capability group is not a lead symbol, then simply 1327 * verify the symbol. 1328 */ 1329 if (grpndx != CAPINFO_SUNW_GLOB) { 1330 Syscapset symcapset = { 0 }; 1331 1332 return (sym_cap_check(cap, grpndx, &symcapset, ilmp, 1333 srp->sr_name, symndx)); 1334 } 1335 1336 /* 1337 * If there is no capabilities chain, return the lead symbol. 1338 */ 1339 if (capchain == NULL) 1340 return (1); 1341 1342 ochainndx = (uint_t)ELF_C_SYM(CAPINFO(ilmp)[symndx]); 1343 1344 /* 1345 * If there is only one member for this family, take it. Once a family 1346 * has been processed, the best family instance is written to the head 1347 * of the chain followed by a null entry. This caching ensures that the 1348 * same family comparison doesn't have to be undertaken more than once. 1349 */ 1350 if (capchain[ochainndx] && (capchain[ochainndx + 1] == 0)) { 1351 Sym *fsym = symtabptr + capchain[ochainndx]; 1352 const char *fname = strtabptr + fsym->st_name; 1353 1354 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, fname, 1355 capchain[ochainndx], M_MACH, NULL)); 1356 1357 srp->sr_sym = fsym; 1358 srp->sr_name = fname; 1359 return (1); 1360 } 1361 1362 /* 1363 * As this symbol is the lead symbol of a capabilities family, it is 1364 * considered the generic member, and therefore forms the basic 1365 * fall-back for the capabilities family. 1366 */ 1367 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_DEFAULT, srp->sr_name, 1368 symndx, M_MACH, NULL)); 1369 bsym = srp->sr_sym; 1370 bname = srp->sr_name; 1371 bndx = symndx; 1372 1373 /* 1374 * Traverse the capabilities chain analyzing each family member. 1375 */ 1376 for (nchainndx = ochainndx + 1, symndx = capchain[nchainndx]; symndx; 1377 nchainndx++, symndx = capchain[nchainndx]) { 1378 Sym *nsym = symtabptr + symndx; 1379 const char *nname = strtabptr + nsym->st_name; 1380 Syscapset symcapset = { 0 }; 1381 1382 if ((grpndx = 1383 (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx])) == 0) 1384 continue; 1385 1386 if (sym_cap_check(cap, grpndx, &symcapset, ilmp, 1387 nname, symndx) == 0) 1388 continue; 1389 1390 /* 1391 * Determine whether a symbol's capabilities are more 1392 * significant than any that have already been validated. 1393 */ 1394 if (is_sym_the_best(&bestcapset, &symcapset)) { 1395 bestcapset = symcapset; 1396 bsym = nsym; 1397 bname = nname; 1398 bndx = symndx; 1399 } 1400 } 1401 1402 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, bname, bndx, 1403 M_MACH, NULL)); 1404 1405 /* 1406 * Having found the best symbol, cache the results by overriding the 1407 * first element of the associated chain. 1408 */ 1409 capchain[ochainndx] = bndx; 1410 capchain[ochainndx + 1] = 0; 1411 1412 /* 1413 * Update the symbol result information for return to the user. 1414 */ 1415 srp->sr_sym = bsym; 1416 srp->sr_name = bname; 1417 return (1); 1418 } 1419