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, const char *ref, int mode, uint_t flags, int *in_nfavl) 656 { 657 Alist *fdalp = NULL; 658 Aliste idx; 659 Fdesc *fdp; 660 Lm_list *lml = LIST(flmp); 661 int unused = 0; 662 Rej_desc rej = { 0 }; 663 664 if (cap_dir(&fdalp, lml, dir, flmp, flags, &rej, in_nfavl) == 0) 665 return (0); 666 667 /* 668 * Now complete the mapping of each of the ordered objects, adding 669 * each object to a new pathname descriptor. 670 */ 671 for (ALIST_TRAVERSE(fdalp, idx, fdp)) { 672 Rt_map *nlmp; 673 Grp_hdl *ghp = NULL; 674 Pdesc *pdp; 675 int audit = 0; 676 677 if (unused) 678 continue; 679 680 /* 681 * Complete mapping the file, obtaining a handle, and continue 682 * to analyze the object, establishing dependencies and 683 * relocating. Remove the file descriptor at this point, as it 684 * is no longer required. 685 */ 686 DBG_CALL(Dbg_file_filtee(lml, NAME(flmp), fdp->fd_nname, 0)); 687 688 nlmp = load_path(lml, nlmco, flmp, mode, 689 (flags | FLG_RT_PUBHDL), &ghp, fdp, &rej, in_nfavl); 690 if (nlmp == NULL) 691 continue; 692 693 /* 694 * Create a new pathname descriptor to represent this filtee, 695 * and insert this descriptor in the Alist following the 696 * hardware descriptor that seeded this processing. 697 */ 698 if ((pdp = alist_insert(alpp, 0, sizeof (Pdesc), 699 AL_CNT_FILTEES, ++oidx)) == NULL) { 700 if (ghp) 701 remove_lmc(lml, flmp, nlmco, NAME(nlmp)); 702 return (0); 703 } 704 705 pdp->pd_pname = NAME(nlmp); 706 pdp->pd_plen = strlen(NAME(nlmp)); 707 708 /* 709 * Establish the filter handle to prevent any recursion. 710 */ 711 if (nlmp && ghp) { 712 ghp->gh_flags |= GPH_FILTEE; 713 pdp->pd_info = (void *)ghp; 714 } 715 716 /* 717 * Audit the filter/filtee established. A return of 0 718 * indicates the auditor wishes to ignore this filtee. 719 */ 720 if (nlmp && (lml->lm_tflags | FLAGS1(flmp)) & 721 LML_TFLG_AUD_OBJFILTER) { 722 if (audit_objfilter(flmp, ref, nlmp, 0) == 0) { 723 audit = 1; 724 nlmp = NULL; 725 } 726 } 727 728 /* 729 * Finish processing the objects associated with this request. 730 */ 731 if (nlmp && ghp && (((nlmp = analyze_lmc(lml, nlmco, nlmp, 732 in_nfavl)) == NULL) || 733 (relocate_lmc(lml, nlmco, flmp, nlmp, in_nfavl) == 0))) 734 nlmp = NULL; 735 736 /* 737 * If the filtee has been successfully processed, then create 738 * an association between the filter and the filtee. This 739 * association provides sufficient information to tear down the 740 * filter and filtee if necessary. 741 */ 742 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); 743 if (nlmp && ghp && 744 (hdl_add(ghp, flmp, GPD_FILTER, NULL) == NULL)) 745 nlmp = NULL; 746 747 /* 748 * If this object is marked an end-filtee, we're done. 749 */ 750 if (nlmp && ghp && (FLAGS1(nlmp) & FL1_RT_ENDFILTE)) 751 unused = 1; 752 753 /* 754 * If this filtee loading has failed, generate a diagnostic. 755 * Null out the path name descriptor entry, and continue the 756 * search. 757 */ 758 if (nlmp == NULL) { 759 DBG_CALL(Dbg_file_filtee(lml, 0, pdp->pd_pname, audit)); 760 761 /* 762 * If attempting to load this filtee required a new 763 * link-map control list to which this request has 764 * added objects, then remove all the objects that 765 * have been associated to this request. 766 */ 767 if (nlmco != ALIST_OFF_DATA) 768 remove_lmc(lml, flmp, nlmco, pdp->pd_pname); 769 770 pdp->pd_plen = 0; 771 pdp->pd_info = NULL; 772 } 773 } 774 775 free_fd(fdalp); 776 return (1); 777 } 778 779 /* 780 * Load an individual capabilities object. 781 */ 782 Rt_map * 783 load_cap(Lm_list *lml, Aliste lmco, const char *dir, Rt_map *clmp, 784 uint_t mode, uint_t flags, Grp_hdl **hdl, Rej_desc *rej, int *in_nfavl) 785 { 786 Alist *fdalp = NULL; 787 Aliste idx; 788 Fdesc *fdp; 789 int found = 0; 790 Rt_map *lmp = NULL; 791 792 /* 793 * Obtain the sorted list of hardware capabilities objects available. 794 */ 795 if (cap_dir(&fdalp, lml, dir, clmp, flags, rej, in_nfavl) == 0) 796 return (NULL); 797 798 /* 799 * From the list of hardware capability objects, use the first and 800 * discard the rest. 801 */ 802 for (ALIST_TRAVERSE(fdalp, idx, fdp)) { 803 Fdesc fd = *fdp; 804 805 if ((found == 0) && ((lmp = load_path(lml, lmco, clmp, mode, 806 flags, hdl, &fd, rej, in_nfavl)) != NULL)) 807 found++; 808 } 809 810 free_fd(fdalp); 811 return (lmp); 812 } 813 814 /* 815 * Use a case insensitive string match when looking up capability mask 816 * values by name, and omit the AV_ prefix. 817 */ 818 #define ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP 819 820 /* 821 * To aid in the development and testing of capabilities, an alternative system 822 * capabilities group can be specified. This alternative set is initialized 823 * from the system capabilities that are normally used to validate all object 824 * loading. However, the user can disable, enable or override flags within 825 * this alternative set, and thus affect object loading. 826 * 827 * This technique is usually combined with defining the family of objects 828 * that should be compared against this alternative set. Without defining the 829 * family of objects, all objects loaded by ld.so.1 are validated against the 830 * alternative set. This can prevent the loading of critical system objects 831 * like libc, and thus prevent process execution. 832 */ 833 typedef enum { 834 CAP_OVERRIDE = 0, /* override existing capabilities */ 835 CAP_ENABLE = 1, /* enable capabilities */ 836 CAP_DISABLE = 2 /* disable capabilities */ 837 } cap_mode; 838 839 static struct { 840 elfcap_mask_t cs_val[3]; /* value settings, and indicator for */ 841 int cs_set[3]; /* OVERRIDE, ENABLE and DISABLE */ 842 elfcap_mask_t *cs_aval; /* alternative variable for final */ 843 /* update */ 844 } cap_settings[3] = { 845 { { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_HW_1 */ 846 { { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_SF_1 */ 847 { { 0, 0, 0 }, { 0, 0, 0 }, NULL } /* CA_SUNW_HW_2 */ 848 }; 849 850 static int 851 cap_modify(Xword tag, const char *str) 852 { 853 char *caps, *ptr, *next; 854 cap_mode mode = CAP_OVERRIDE; 855 Xword ndx; 856 857 if ((caps = strdup(str)) == NULL) 858 return (0); 859 860 ptr = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next); 861 do { 862 Xword val = 0; 863 864 /* 865 * Determine whether this token should be enabled (+), 866 * disabled (-), or override any existing settings. 867 */ 868 if (*ptr == '+') { 869 mode = CAP_ENABLE; 870 ptr++; 871 } else if (*ptr == '-') { 872 mode = CAP_DISABLE; 873 ptr++; 874 } 875 876 /* 877 * Process the capabilities as directed by the calling tag. 878 */ 879 switch (tag) { 880 case CA_SUNW_HW_1: 881 /* 882 * Determine whether the capabilities string matches 883 * a known hardware capability mask. Note, the caller 884 * indicates that these are hardware capabilities by 885 * passing in the CA_SUNW_HW_1 tag. However, the 886 * tokens could be CA_SUNW_HW_1 or CA_SUNW_HW_2. 887 */ 888 if ((val = (Xword)elfcap_hw2_from_str(ELFCAP_STYLE, 889 ptr, M_MACH)) != 0) { 890 ndx = CA_SUNW_HW_2; 891 break; 892 } 893 if ((val = (Xword)elfcap_hw1_from_str(ELFCAP_STYLE, 894 ptr, M_MACH)) != 0) 895 ndx = CA_SUNW_HW_1; 896 break; 897 case CA_SUNW_SF_1: 898 /* 899 * Determine whether the capabilities string matches a 900 * known software capability mask. Note, the callers 901 * indication of what capabilities to process are 902 * triggered by a tag of CA_SUNW_SF_1, but the tokens 903 * processed could be CA_SUNW_SF_1, CA_SUNW_SF_2, etc. 904 */ 905 if ((val = (Xword)elfcap_sf1_from_str(ELFCAP_STYLE, 906 ptr, M_MACH)) != 0) 907 ndx = CA_SUNW_SF_1; 908 break; 909 } 910 911 /* 912 * If a capabilities token has not been matched, interpret the 913 * string as a number. To provide for setting the various 914 * families (CA_SUNW_HW_1, CA_SUNW_HW_2), the number can be 915 * prefixed with the (bracketed) family index. 916 * 917 * LD_HWCAP=[1]0x40 sets CA_SUNW_HW_1 with 0x40 918 * LD_HWCAP=[2]0x80 sets CA_SUNW_HW_2 with 0x80 919 * 920 * Invalid indexes are ignored. 921 */ 922 if (val == 0) { 923 if ((*ptr == '[') && (*(ptr + 2) == ']')) { 924 if (*(ptr + 1) == '1') { 925 ndx = tag; 926 ptr += 3; 927 } else if (*(ptr + 1) == '2') { 928 if (tag == CA_SUNW_HW_1) { 929 ndx = CA_SUNW_HW_2; 930 ptr += 3; 931 } else { 932 /* invalid index */ 933 continue; 934 } 935 } else { 936 /* invalid index */ 937 continue; 938 } 939 } else 940 ndx = tag; 941 942 errno = 0; 943 if (((val = strtol(ptr, NULL, 16)) == 0) && errno) 944 continue; 945 } 946 cap_settings[ndx - 1].cs_val[mode] |= val; 947 cap_settings[ndx - 1].cs_set[mode]++; 948 949 } while ((ptr = strtok_r(NULL, 950 MSG_ORIG(MSG_CAP_DELIMIT), &next)) != NULL); 951 952 /* 953 * If the "override" token was supplied, set the alternative 954 * system capabilities, then enable or disable others. 955 */ 956 for (ndx = 0; ndx < CA_SUNW_HW_2; ndx++) { 957 if (cap_settings[ndx].cs_set[CAP_OVERRIDE]) 958 *(cap_settings[ndx].cs_aval) = 959 cap_settings[ndx].cs_val[CAP_OVERRIDE]; 960 if (cap_settings[ndx].cs_set[CAP_ENABLE]) 961 *(cap_settings[ndx].cs_aval) |= 962 cap_settings[ndx].cs_val[CAP_ENABLE]; 963 if (cap_settings[ndx].cs_set[CAP_DISABLE]) 964 *(cap_settings[ndx].cs_aval) &= 965 ~cap_settings[ndx].cs_val[CAP_DISABLE]; 966 } 967 free(caps); 968 return (1); 969 } 970 #undef ELFCAP_STYLE 971 972 /* 973 * Create an AVL tree of objects that are to be validated against an alternative 974 * system capabilities value. 975 */ 976 static int 977 cap_files(const char *str) 978 { 979 char *caps, *name, *next; 980 981 if ((caps = strdup(str)) == NULL) 982 return (0); 983 984 name = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next); 985 do { 986 avl_index_t where; 987 PathNode *pnp; 988 uint_t hash = sgs_str_hash(name); 989 990 /* 991 * Determine whether this pathname has already been recorded. 992 */ 993 if (pnavl_recorded(&capavl, name, hash, &where)) 994 continue; 995 996 if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) { 997 pnp->pn_name = name; 998 pnp->pn_hash = hash; 999 avl_insert(capavl, pnp, where); 1000 } 1001 } while ((name = strtok_r(NULL, 1002 MSG_ORIG(MSG_CAP_DELIMIT), &next)) != NULL); 1003 1004 return (1); 1005 } 1006 1007 /* 1008 * Set alternative system capabilities. A user can establish alternative system 1009 * capabilities from the environment, or from a configuration file. This 1010 * routine is called in each instance. Environment variables only set the 1011 * replaceable (rpl) variables. Configuration files can set both replaceable 1012 * (rpl) and permanent (prm) variables. 1013 */ 1014 int 1015 cap_alternative(void) 1016 { 1017 /* 1018 * If no capabilities have been set, we're done. 1019 */ 1020 if ((rpl_hwcap == NULL) && (rpl_sfcap == NULL) && 1021 (rpl_machcap == NULL) && (rpl_platcap == NULL) && 1022 (prm_hwcap == NULL) && (prm_sfcap == NULL) && 1023 (prm_machcap == NULL) && (prm_platcap == NULL)) 1024 return (1); 1025 1026 /* 1027 * If the user has requested to modify any capabilities, establish a 1028 * unique set from the present system capabilities. 1029 */ 1030 if ((alt_scapset = malloc(sizeof (Syscapset))) == NULL) 1031 return (0); 1032 *alt_scapset = *org_scapset; 1033 1034 cap_settings[CA_SUNW_HW_1 - 1].cs_aval = &alt_scapset->sc_hw_1; 1035 cap_settings[CA_SUNW_SF_1 - 1].cs_aval = &alt_scapset->sc_sf_1; 1036 cap_settings[CA_SUNW_HW_2 - 1].cs_aval = &alt_scapset->sc_hw_2; 1037 1038 /* 1039 * Process any replaceable variables. 1040 */ 1041 if (rpl_hwcap && (cap_modify(CA_SUNW_HW_1, rpl_hwcap) == 0)) 1042 return (0); 1043 if (rpl_sfcap && (cap_modify(CA_SUNW_SF_1, rpl_sfcap) == 0)) 1044 return (0); 1045 1046 if (rpl_platcap) { 1047 alt_scapset->sc_plat = (char *)rpl_platcap; 1048 alt_scapset->sc_platsz = strlen(rpl_platcap); 1049 } 1050 if (rpl_machcap) { 1051 alt_scapset->sc_mach = (char *)rpl_machcap; 1052 alt_scapset->sc_machsz = strlen(rpl_machcap); 1053 } 1054 1055 if (rpl_cap_files && (cap_files(rpl_cap_files) == 0)) 1056 return (0); 1057 1058 /* 1059 * Process any permanent variables. 1060 */ 1061 if (prm_hwcap && (cap_modify(CA_SUNW_HW_1, prm_hwcap) == 0)) 1062 return (0); 1063 if (prm_sfcap && (cap_modify(CA_SUNW_SF_1, prm_sfcap) == 0)) 1064 return (0); 1065 1066 if (prm_platcap) { 1067 alt_scapset->sc_plat = (char *)prm_platcap; 1068 alt_scapset->sc_platsz = strlen(prm_platcap); 1069 } 1070 if (prm_machcap) { 1071 alt_scapset->sc_mach = (char *)prm_machcap; 1072 alt_scapset->sc_machsz = strlen(prm_machcap); 1073 } 1074 1075 if (prm_cap_files && (cap_files(prm_cap_files) == 0)) 1076 return (0); 1077 1078 /* 1079 * Reset the replaceable variables. If this is the environment variable 1080 * processing, these variables are now available for configuration file 1081 * initialization. 1082 */ 1083 rpl_hwcap = rpl_sfcap = rpl_machcap = rpl_platcap = 1084 rpl_cap_files = NULL; 1085 1086 return (1); 1087 } 1088 1089 /* 1090 * Take the index from a Capinfo entry and determine the associated capabilities 1091 * set. Verify that the capabilities are available for this system. 1092 */ 1093 static int 1094 sym_cap_check(Cap *cptr, uint_t cndx, Syscapset *bestcapset, Rt_map *lmp, 1095 const char *name, uint_t ndx) 1096 { 1097 Syscapset *scapset; 1098 int totplat, ivlplat, totmach, ivlmach, capfail = 0; 1099 1100 /* 1101 * Determine whether this file requires validation against alternative 1102 * system capabilities. 1103 */ 1104 if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0) 1105 cap_check_lmp_init(lmp); 1106 1107 if (FLAGS1(lmp) & FL1_RT_ALTCAP) 1108 scapset = alt_scapset; 1109 else 1110 scapset = org_scapset; 1111 1112 totplat = ivlplat = totmach = ivlmach = 0; 1113 1114 /* 1115 * A capabilities index points to a capabilities group that can consist 1116 * of one or more capabilities, terminated with a CA_SUNW_NULL entry. 1117 */ 1118 for (cptr += cndx; cptr->c_tag != CA_SUNW_NULL; cptr++) { 1119 Xword val = cptr->c_un.c_val; 1120 char *str; 1121 1122 switch (cptr->c_tag) { 1123 case CA_SUNW_HW_1: 1124 /* 1125 * Remove any historic values that should not be 1126 * involved with any validation. 1127 */ 1128 val &= ~AV_HW1_IGNORE; 1129 1130 bestcapset->sc_hw_1 = val; 1131 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_1, 1132 name, ndx, M_MACH, bestcapset)); 1133 1134 if (hwcap1_check(scapset, val, NULL) == 0) 1135 capfail++; 1136 break; 1137 case CA_SUNW_SF_1: 1138 bestcapset->sc_sf_1 = val; 1139 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_SF_1, 1140 name, ndx, M_MACH, bestcapset)); 1141 1142 if (sfcap1_check(scapset, val, NULL) == 0) 1143 capfail++; 1144 break; 1145 case CA_SUNW_HW_2: 1146 bestcapset->sc_hw_2 = val; 1147 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_2, 1148 name, ndx, M_MACH, bestcapset)); 1149 1150 if (hwcap2_check(scapset, val, NULL) == 0) 1151 capfail++; 1152 break; 1153 case CA_SUNW_PLAT: 1154 /* 1155 * A capabilities set can define multiple platform names 1156 * that are appropriate. Only if all the names are 1157 * deemed invalid is the group determined inappropriate. 1158 */ 1159 if (totplat == ivlplat) { 1160 totplat++; 1161 1162 str = STRTAB(lmp) + val; 1163 bestcapset->sc_plat = str; 1164 1165 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_PLAT, 1166 name, ndx, M_MACH, bestcapset)); 1167 1168 if (platcap_check(scapset, str, NULL) == 0) 1169 ivlplat++; 1170 } 1171 break; 1172 case CA_SUNW_MACH: 1173 /* 1174 * A capabilities set can define multiple machine names 1175 * that are appropriate. Only if all the names are 1176 * deemed invalid is the group determined inappropriate. 1177 */ 1178 if (totmach == ivlmach) { 1179 totmach++; 1180 1181 str = STRTAB(lmp) + val; 1182 bestcapset->sc_mach = str; 1183 1184 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_MACH, 1185 name, ndx, M_MACH, bestcapset)); 1186 1187 if (machcap_check(scapset, str, NULL) == 0) 1188 ivlmach++; 1189 } 1190 break; 1191 default: 1192 break; 1193 } 1194 } 1195 1196 /* 1197 * If any platform definitions, or machine definitions were found, and 1198 * all were invalid, indicate that the object is inappropriate. 1199 */ 1200 if (capfail || (totplat && (totplat == ivlplat)) || 1201 (totmach && (totmach == ivlmach))) { 1202 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_REJECTED, name, ndx, 1203 M_MACH, NULL)); 1204 return (0); 1205 } 1206 1207 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_CANDIDATE, name, ndx, 1208 M_MACH, NULL)); 1209 return (1); 1210 } 1211 1212 /* 1213 * Determine whether a symbols capabilities are more significant than any that 1214 * have already been validated. The precedence of capabilities are: 1215 * 1216 * PLATCAP -> MACHCAP -> HWCAP_2 -> HWCAP_1 1217 * 1218 * 1219 * Presently we make no comparisons of software capabilities. However, should 1220 * this symbol capability have required the SF1_SUNW_ADDR32 attribute, then 1221 * this would have been validated as appropriate or not. 1222 * 1223 * bestcapset is the presently available 'best' capabilities group, and 1224 * symcapset is the present capabilities group under investigation. Return 0 1225 * if the bestcapset should remain in affect, or 1 if the symcapset is better. 1226 */ 1227 inline static int 1228 is_sym_the_best(Syscapset *bestcapset, Syscapset *symcapset) 1229 { 1230 /* 1231 * Check any platform capability. If the new symbol isn't associated 1232 * with a CA_SUNW_PLAT capability, and the best symbol is, then retain 1233 * the best capabilities group. If the new symbol is associated with a 1234 * CA_SUNW_PLAT capability, and the best symbol isn't, then the new 1235 * symbol needs to be taken. 1236 */ 1237 if (bestcapset->sc_plat && (symcapset->sc_plat == NULL)) 1238 return (0); 1239 1240 if ((bestcapset->sc_plat == NULL) && symcapset->sc_plat) 1241 return (1); 1242 1243 /* 1244 * Check any machine name capability. If the new symbol isn't 1245 * associated with a CA_SUNW_MACH capability, and the best symbol is, 1246 * then retain the best capabilities group. If the new symbol is 1247 * associated with a CA_SUNW_MACH capability, and the best symbol isn't, 1248 * then the new symbol needs to be taken. 1249 */ 1250 if (bestcapset->sc_mach && (symcapset->sc_mach == NULL)) 1251 return (0); 1252 1253 if ((bestcapset->sc_mach == NULL) && symcapset->sc_mach) 1254 return (1); 1255 1256 /* 1257 * Check the hardware capabilities. If the best symbols CA_SUNW_HW_2 1258 * capabilities are greater than the new symbols capabilities, then 1259 * retain the best capabilities group. If the new symbols CA_SUNW_HW_2 1260 * capabilities are greater than the best symbol, then the new symbol 1261 * needs to be taken. 1262 */ 1263 if (bestcapset->sc_hw_2 > symcapset->sc_hw_2) 1264 return (0); 1265 1266 if (bestcapset->sc_hw_2 < symcapset->sc_hw_2) 1267 return (1); 1268 1269 /* 1270 * Check the remaining hardware capabilities. If the best symbols 1271 * CA_SUNW_HW_1 capabilities are greater than the new symbols 1272 * capabilities, then retain the best capabilities group. If the new 1273 * symbols CA_SUNW_HW_1 capabilities are greater than the best symbol, 1274 * then the new symbol needs to be taken. 1275 */ 1276 if (bestcapset->sc_hw_1 > symcapset->sc_hw_1) 1277 return (0); 1278 1279 if (bestcapset->sc_hw_1 < symcapset->sc_hw_1) 1280 return (1); 1281 1282 /* 1283 * Both capabilities are the same. Retain the best on a first-come 1284 * first-served basis. 1285 */ 1286 return (0); 1287 } 1288 1289 /* 1290 * Initiate symbol capabilities processing. If an initial symbol lookup 1291 * results in binding to a symbol that has an associated SUNW_capinfo entry, 1292 * we arrive here. 1293 * 1294 * The standard model is that this initial symbol is the lead capabilities 1295 * symbol (defined as CAPINFO_SUNW_GLOB) of a capabilities family. This lead 1296 * symbol's SUNW_capinfo information points to the SUNW_capchain entry that 1297 * provides the family symbol indexes. We traverse this chain, looking at 1298 * each family member, to discover the best capabilities instance. This 1299 * instance name and symbol information is returned to establish the final 1300 * symbol binding. 1301 * 1302 * If the symbol that got us here is not CAPINFO_SUNW_GLOB, then we've bound 1303 * directly to a capabilities symbol which must be verified. This is not the 1304 * model created by ld(1) using -z symbolcap, but might be created directly 1305 * within a relocatable object by the compilation system. 1306 */ 1307 int 1308 cap_match(Sresult *srp, uint_t symndx, Sym *symtabptr, char *strtabptr) 1309 { 1310 Rt_map *ilmp = srp->sr_dmap; 1311 Sym *bsym = NULL; 1312 const char *bname; 1313 Syscapset bestcapset = { 0 }; 1314 Cap *cap; 1315 Capchain *capchain; 1316 uchar_t grpndx; 1317 uint_t ochainndx, nchainndx, bndx; 1318 1319 cap = CAP(ilmp); 1320 capchain = CAPCHAIN(ilmp); 1321 1322 grpndx = (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx]); 1323 1324 /* 1325 * If this symbols capability group is not a lead symbol, then simply 1326 * verify the symbol. 1327 */ 1328 if (grpndx != CAPINFO_SUNW_GLOB) { 1329 Syscapset symcapset = { 0 }; 1330 1331 return (sym_cap_check(cap, grpndx, &symcapset, ilmp, 1332 srp->sr_name, symndx)); 1333 } 1334 1335 /* 1336 * If there is no capabilities chain, return the lead symbol. 1337 */ 1338 if (capchain == NULL) 1339 return (1); 1340 1341 ochainndx = (uint_t)ELF_C_SYM(CAPINFO(ilmp)[symndx]); 1342 1343 /* 1344 * If there is only one member for this family, take it. Once a family 1345 * has been processed, the best family instance is written to the head 1346 * of the chain followed by a null entry. This caching ensures that the 1347 * same family comparison doesn't have to be undertaken more than once. 1348 */ 1349 if (capchain[ochainndx] && (capchain[ochainndx + 1] == 0)) { 1350 Sym *fsym = symtabptr + capchain[ochainndx]; 1351 const char *fname = strtabptr + fsym->st_name; 1352 1353 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, fname, 1354 capchain[ochainndx], M_MACH, NULL)); 1355 1356 srp->sr_sym = fsym; 1357 srp->sr_name = fname; 1358 return (1); 1359 } 1360 1361 /* 1362 * As this symbol is the lead symbol of a capabilities family, it is 1363 * considered the generic member, and therefore forms the basic 1364 * fall-back for the capabilities family. 1365 */ 1366 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_DEFAULT, srp->sr_name, 1367 symndx, M_MACH, NULL)); 1368 bsym = srp->sr_sym; 1369 bname = srp->sr_name; 1370 bndx = symndx; 1371 1372 /* 1373 * Traverse the capabilities chain analyzing each family member. 1374 */ 1375 for (nchainndx = ochainndx + 1, symndx = capchain[nchainndx]; symndx; 1376 nchainndx++, symndx = capchain[nchainndx]) { 1377 Sym *nsym = symtabptr + symndx; 1378 const char *nname = strtabptr + nsym->st_name; 1379 Syscapset symcapset = { 0 }; 1380 1381 if ((grpndx = 1382 (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx])) == 0) 1383 continue; 1384 1385 if (sym_cap_check(cap, grpndx, &symcapset, ilmp, 1386 nname, symndx) == 0) 1387 continue; 1388 1389 /* 1390 * Determine whether a symbol's capabilities are more 1391 * significant than any that have already been validated. 1392 */ 1393 if (is_sym_the_best(&bestcapset, &symcapset)) { 1394 bestcapset = symcapset; 1395 bsym = nsym; 1396 bname = nname; 1397 bndx = symndx; 1398 } 1399 } 1400 1401 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, bname, bndx, 1402 M_MACH, NULL)); 1403 1404 /* 1405 * Having found the best symbol, cache the results by overriding the 1406 * first element of the associated chain. 1407 */ 1408 capchain[ochainndx] = bndx; 1409 capchain[ochainndx + 1] = 0; 1410 1411 /* 1412 * Update the symbol result information for return to the user. 1413 */ 1414 srp->sr_sym = bsym; 1415 srp->sr_name = bname; 1416 return (1); 1417 } 1418