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, 0, 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 for (ptr = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next); 862 ptr != NULL; 863 ptr = strtok_r(NULL, MSG_ORIG(MSG_CAP_DELIMIT), &next)) { 864 Xword val = 0; 865 866 /* 867 * Determine whether this token should be enabled (+), 868 * disabled (-), or override any existing settings. 869 */ 870 if (*ptr == '+') { 871 mode = CAP_ENABLE; 872 ptr++; 873 } else if (*ptr == '-') { 874 mode = CAP_DISABLE; 875 ptr++; 876 } 877 878 /* 879 * Process the capabilities as directed by the calling tag. 880 */ 881 switch (tag) { 882 case CA_SUNW_HW_1: 883 /* 884 * Determine whether the capabilities string matches 885 * a known hardware capability mask. Note, the caller 886 * indicates that these are hardware capabilities by 887 * passing in the CA_SUNW_HW_1 tag. However, the 888 * tokens could be CA_SUNW_HW_1 or CA_SUNW_HW_2. 889 */ 890 if ((val = (Xword)elfcap_hw2_from_str(ELFCAP_STYLE, 891 ptr, M_MACH)) != 0) { 892 ndx = CA_SUNW_HW_2; 893 break; 894 } 895 if ((val = (Xword)elfcap_hw1_from_str(ELFCAP_STYLE, 896 ptr, M_MACH)) != 0) 897 ndx = CA_SUNW_HW_1; 898 break; 899 case CA_SUNW_SF_1: 900 /* 901 * Determine whether the capabilities string matches a 902 * known software capability mask. Note, the callers 903 * indication of what capabilities to process are 904 * triggered by a tag of CA_SUNW_SF_1, but the tokens 905 * processed could be CA_SUNW_SF_1, CA_SUNW_SF_2, etc. 906 */ 907 if ((val = (Xword)elfcap_sf1_from_str(ELFCAP_STYLE, 908 ptr, M_MACH)) != 0) 909 ndx = CA_SUNW_SF_1; 910 break; 911 } 912 913 /* 914 * If a capabilities token has not been matched, interpret the 915 * string as a number. To provide for setting the various 916 * families (CA_SUNW_HW_1, CA_SUNW_HW_2), the number can be 917 * prefixed with the (bracketed) family index. 918 * 919 * LD_HWCAP=[1]0x40 sets CA_SUNW_HW_1 with 0x40 920 * LD_HWCAP=[2]0x80 sets CA_SUNW_HW_2 with 0x80 921 * 922 * Invalid indexes are ignored. 923 */ 924 if (val == 0) { 925 char *end; 926 927 if ((*ptr == '[') && (*(ptr + 2) == ']')) { 928 if (*(ptr + 1) == '1') { 929 ndx = tag; 930 ptr += 3; 931 } else if (*(ptr + 1) == '2') { 932 if (tag == CA_SUNW_HW_1) { 933 ndx = CA_SUNW_HW_2; 934 ptr += 3; 935 } else { 936 /* invalid index */ 937 continue; 938 } 939 } else { 940 /* invalid index */ 941 continue; 942 } 943 } else 944 ndx = tag; 945 946 errno = 0; 947 if (((val = strtol(ptr, &end, 16)) == 0) && errno) 948 continue; 949 950 /* 951 * If the value wasn't an entirely valid hexadecimal 952 * integer, assume it was intended as a capability 953 * name and skip it. 954 */ 955 if (*end != '\0') { 956 eprintf(NULL, ERR_WARNING, 957 MSG_INTL(MSG_CAP_IGN_UNKCAP), ptr); 958 continue; 959 } 960 } 961 962 cap_settings[ndx - 1].cs_val[mode] |= val; 963 cap_settings[ndx - 1].cs_set[mode]++; 964 965 } 966 967 /* 968 * If the "override" token was supplied, set the alternative 969 * system capabilities, then enable or disable others. 970 */ 971 for (ndx = 0; ndx < CA_SUNW_HW_2; ndx++) { 972 if (cap_settings[ndx].cs_set[CAP_OVERRIDE]) 973 *(cap_settings[ndx].cs_aval) = 974 cap_settings[ndx].cs_val[CAP_OVERRIDE]; 975 if (cap_settings[ndx].cs_set[CAP_ENABLE]) 976 *(cap_settings[ndx].cs_aval) |= 977 cap_settings[ndx].cs_val[CAP_ENABLE]; 978 if (cap_settings[ndx].cs_set[CAP_DISABLE]) 979 *(cap_settings[ndx].cs_aval) &= 980 ~cap_settings[ndx].cs_val[CAP_DISABLE]; 981 } 982 free(caps); 983 return (1); 984 } 985 #undef ELFCAP_STYLE 986 987 /* 988 * Create an AVL tree of objects that are to be validated against an alternative 989 * system capabilities value. 990 */ 991 static int 992 cap_files(const char *str) 993 { 994 char *caps, *name, *next; 995 996 if ((caps = strdup(str)) == NULL) 997 return (0); 998 999 for (name = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next); 1000 name != NULL; 1001 name = strtok_r(NULL, MSG_ORIG(MSG_CAP_DELIMIT), &next)) { 1002 avl_index_t where; 1003 PathNode *pnp; 1004 uint_t hash = sgs_str_hash(name); 1005 1006 /* 1007 * Determine whether this pathname has already been recorded. 1008 */ 1009 if (pnavl_recorded(&capavl, name, hash, &where)) 1010 continue; 1011 1012 if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) { 1013 pnp->pn_name = name; 1014 pnp->pn_hash = hash; 1015 avl_insert(capavl, pnp, where); 1016 } 1017 } 1018 1019 return (1); 1020 } 1021 1022 /* 1023 * Set alternative system capabilities. A user can establish alternative system 1024 * capabilities from the environment, or from a configuration file. This 1025 * routine is called in each instance. Environment variables only set the 1026 * replaceable (rpl) variables. Configuration files can set both replaceable 1027 * (rpl) and permanent (prm) variables. 1028 */ 1029 int 1030 cap_alternative(void) 1031 { 1032 /* 1033 * If no capabilities have been set, we're done. 1034 */ 1035 if ((rpl_hwcap == NULL) && (rpl_sfcap == NULL) && 1036 (rpl_machcap == NULL) && (rpl_platcap == NULL) && 1037 (prm_hwcap == NULL) && (prm_sfcap == NULL) && 1038 (prm_machcap == NULL) && (prm_platcap == NULL)) 1039 return (1); 1040 1041 /* 1042 * If the user has requested to modify any capabilities, establish a 1043 * unique set from the present system capabilities. 1044 */ 1045 if ((alt_scapset = malloc(sizeof (Syscapset))) == NULL) 1046 return (0); 1047 *alt_scapset = *org_scapset; 1048 1049 cap_settings[CA_SUNW_HW_1 - 1].cs_aval = &alt_scapset->sc_hw_1; 1050 cap_settings[CA_SUNW_SF_1 - 1].cs_aval = &alt_scapset->sc_sf_1; 1051 cap_settings[CA_SUNW_HW_2 - 1].cs_aval = &alt_scapset->sc_hw_2; 1052 1053 /* 1054 * Process any replaceable variables. 1055 */ 1056 if (rpl_hwcap && (cap_modify(CA_SUNW_HW_1, rpl_hwcap) == 0)) 1057 return (0); 1058 if (rpl_sfcap && (cap_modify(CA_SUNW_SF_1, rpl_sfcap) == 0)) 1059 return (0); 1060 1061 if (rpl_platcap) { 1062 alt_scapset->sc_plat = (char *)rpl_platcap; 1063 alt_scapset->sc_platsz = strlen(rpl_platcap); 1064 } 1065 if (rpl_machcap) { 1066 alt_scapset->sc_mach = (char *)rpl_machcap; 1067 alt_scapset->sc_machsz = strlen(rpl_machcap); 1068 } 1069 1070 if (rpl_cap_files && (cap_files(rpl_cap_files) == 0)) 1071 return (0); 1072 1073 /* 1074 * Process any permanent variables. 1075 */ 1076 if (prm_hwcap && (cap_modify(CA_SUNW_HW_1, prm_hwcap) == 0)) 1077 return (0); 1078 if (prm_sfcap && (cap_modify(CA_SUNW_SF_1, prm_sfcap) == 0)) 1079 return (0); 1080 1081 if (prm_platcap) { 1082 alt_scapset->sc_plat = (char *)prm_platcap; 1083 alt_scapset->sc_platsz = strlen(prm_platcap); 1084 } 1085 if (prm_machcap) { 1086 alt_scapset->sc_mach = (char *)prm_machcap; 1087 alt_scapset->sc_machsz = strlen(prm_machcap); 1088 } 1089 1090 if (prm_cap_files && (cap_files(prm_cap_files) == 0)) 1091 return (0); 1092 1093 /* 1094 * Reset the replaceable variables. If this is the environment variable 1095 * processing, these variables are now available for configuration file 1096 * initialization. 1097 */ 1098 rpl_hwcap = rpl_sfcap = rpl_machcap = rpl_platcap = 1099 rpl_cap_files = NULL; 1100 1101 return (1); 1102 } 1103 1104 /* 1105 * Take the index from a Capinfo entry and determine the associated capabilities 1106 * set. Verify that the capabilities are available for this system. 1107 */ 1108 static int 1109 sym_cap_check(Cap *cptr, uint_t cndx, Syscapset *bestcapset, Rt_map *lmp, 1110 const char *name, uint_t ndx) 1111 { 1112 Syscapset *scapset; 1113 int totplat, ivlplat, totmach, ivlmach, capfail = 0; 1114 1115 /* 1116 * Determine whether this file requires validation against alternative 1117 * system capabilities. 1118 */ 1119 if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0) 1120 cap_check_lmp_init(lmp); 1121 1122 if (FLAGS1(lmp) & FL1_RT_ALTCAP) 1123 scapset = alt_scapset; 1124 else 1125 scapset = org_scapset; 1126 1127 totplat = ivlplat = totmach = ivlmach = 0; 1128 1129 /* 1130 * A capabilities index points to a capabilities group that can consist 1131 * of one or more capabilities, terminated with a CA_SUNW_NULL entry. 1132 */ 1133 for (cptr += cndx; cptr->c_tag != CA_SUNW_NULL; cptr++) { 1134 Xword val = cptr->c_un.c_val; 1135 char *str; 1136 1137 switch (cptr->c_tag) { 1138 case CA_SUNW_HW_1: 1139 /* 1140 * Remove any historic values that should not be 1141 * involved with any validation. 1142 */ 1143 val &= ~AV_HW1_IGNORE; 1144 1145 bestcapset->sc_hw_1 = val; 1146 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_1, 1147 name, ndx, M_MACH, bestcapset)); 1148 1149 if (hwcap1_check(scapset, val, NULL) == 0) 1150 capfail++; 1151 break; 1152 case CA_SUNW_SF_1: 1153 bestcapset->sc_sf_1 = val; 1154 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_SF_1, 1155 name, ndx, M_MACH, bestcapset)); 1156 1157 if (sfcap1_check(scapset, val, NULL) == 0) 1158 capfail++; 1159 break; 1160 case CA_SUNW_HW_2: 1161 bestcapset->sc_hw_2 = val; 1162 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_2, 1163 name, ndx, M_MACH, bestcapset)); 1164 1165 if (hwcap2_check(scapset, val, NULL) == 0) 1166 capfail++; 1167 break; 1168 case CA_SUNW_PLAT: 1169 /* 1170 * A capabilities set can define multiple platform names 1171 * that are appropriate. Only if all the names are 1172 * deemed invalid is the group determined inappropriate. 1173 */ 1174 if (totplat == ivlplat) { 1175 totplat++; 1176 1177 str = STRTAB(lmp) + val; 1178 bestcapset->sc_plat = str; 1179 1180 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_PLAT, 1181 name, ndx, M_MACH, bestcapset)); 1182 1183 if (platcap_check(scapset, str, NULL) == 0) 1184 ivlplat++; 1185 } 1186 break; 1187 case CA_SUNW_MACH: 1188 /* 1189 * A capabilities set can define multiple machine names 1190 * that are appropriate. Only if all the names are 1191 * deemed invalid is the group determined inappropriate. 1192 */ 1193 if (totmach == ivlmach) { 1194 totmach++; 1195 1196 str = STRTAB(lmp) + val; 1197 bestcapset->sc_mach = str; 1198 1199 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_MACH, 1200 name, ndx, M_MACH, bestcapset)); 1201 1202 if (machcap_check(scapset, str, NULL) == 0) 1203 ivlmach++; 1204 } 1205 break; 1206 default: 1207 break; 1208 } 1209 } 1210 1211 /* 1212 * If any platform definitions, or machine definitions were found, and 1213 * all were invalid, indicate that the object is inappropriate. 1214 */ 1215 if (capfail || (totplat && (totplat == ivlplat)) || 1216 (totmach && (totmach == ivlmach))) { 1217 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_REJECTED, name, ndx, 1218 M_MACH, NULL)); 1219 return (0); 1220 } 1221 1222 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_CANDIDATE, name, ndx, 1223 M_MACH, NULL)); 1224 return (1); 1225 } 1226 1227 /* 1228 * Determine whether a symbols capabilities are more significant than any that 1229 * have already been validated. The precedence of capabilities are: 1230 * 1231 * PLATCAP -> MACHCAP -> HWCAP_2 -> HWCAP_1 1232 * 1233 * 1234 * Presently we make no comparisons of software capabilities. However, should 1235 * this symbol capability have required the SF1_SUNW_ADDR32 attribute, then 1236 * this would have been validated as appropriate or not. 1237 * 1238 * bestcapset is the presently available 'best' capabilities group, and 1239 * symcapset is the present capabilities group under investigation. Return 0 1240 * if the bestcapset should remain in affect, or 1 if the symcapset is better. 1241 */ 1242 inline static int 1243 is_sym_the_best(Syscapset *bestcapset, Syscapset *symcapset) 1244 { 1245 /* 1246 * Check any platform capability. If the new symbol isn't associated 1247 * with a CA_SUNW_PLAT capability, and the best symbol is, then retain 1248 * the best capabilities group. If the new symbol is associated with a 1249 * CA_SUNW_PLAT capability, and the best symbol isn't, then the new 1250 * symbol needs to be taken. 1251 */ 1252 if (bestcapset->sc_plat && (symcapset->sc_plat == NULL)) 1253 return (0); 1254 1255 if ((bestcapset->sc_plat == NULL) && symcapset->sc_plat) 1256 return (1); 1257 1258 /* 1259 * Check any machine name capability. If the new symbol isn't 1260 * associated with a CA_SUNW_MACH capability, and the best symbol is, 1261 * then retain the best capabilities group. If the new symbol is 1262 * associated with a CA_SUNW_MACH capability, and the best symbol isn't, 1263 * then the new symbol needs to be taken. 1264 */ 1265 if (bestcapset->sc_mach && (symcapset->sc_mach == NULL)) 1266 return (0); 1267 1268 if ((bestcapset->sc_mach == NULL) && symcapset->sc_mach) 1269 return (1); 1270 1271 /* 1272 * Check the hardware capabilities. If the best symbols CA_SUNW_HW_2 1273 * capabilities are greater than the new symbols capabilities, then 1274 * retain the best capabilities group. If the new symbols CA_SUNW_HW_2 1275 * capabilities are greater than the best symbol, then the new symbol 1276 * needs to be taken. 1277 */ 1278 if (bestcapset->sc_hw_2 > symcapset->sc_hw_2) 1279 return (0); 1280 1281 if (bestcapset->sc_hw_2 < symcapset->sc_hw_2) 1282 return (1); 1283 1284 /* 1285 * Check the remaining hardware capabilities. If the best symbols 1286 * CA_SUNW_HW_1 capabilities are greater than the new symbols 1287 * capabilities, then retain the best capabilities group. If the new 1288 * symbols CA_SUNW_HW_1 capabilities are greater than the best symbol, 1289 * then the new symbol needs to be taken. 1290 */ 1291 if (bestcapset->sc_hw_1 > symcapset->sc_hw_1) 1292 return (0); 1293 1294 if (bestcapset->sc_hw_1 < symcapset->sc_hw_1) 1295 return (1); 1296 1297 /* 1298 * Both capabilities are the same. Retain the best on a first-come 1299 * first-served basis. 1300 */ 1301 return (0); 1302 } 1303 1304 /* 1305 * Initiate symbol capabilities processing. If an initial symbol lookup 1306 * results in binding to a symbol that has an associated SUNW_capinfo entry, 1307 * we arrive here. 1308 * 1309 * The standard model is that this initial symbol is the lead capabilities 1310 * symbol (defined as CAPINFO_SUNW_GLOB) of a capabilities family. This lead 1311 * symbol's SUNW_capinfo information points to the SUNW_capchain entry that 1312 * provides the family symbol indexes. We traverse this chain, looking at 1313 * each family member, to discover the best capabilities instance. This 1314 * instance name and symbol information is returned to establish the final 1315 * symbol binding. 1316 * 1317 * If the symbol that got us here is not CAPINFO_SUNW_GLOB, then we've bound 1318 * directly to a capabilities symbol which must be verified. This is not the 1319 * model created by ld(1) using -z symbolcap, but might be created directly 1320 * within a relocatable object by the compilation system. 1321 */ 1322 int 1323 cap_match(Sresult *srp, uint_t symndx, Sym *symtabptr, char *strtabptr) 1324 { 1325 Rt_map *ilmp = srp->sr_dmap; 1326 Sym *bsym = NULL; 1327 const char *bname; 1328 Syscapset bestcapset = { 0 }; 1329 Cap *cap; 1330 Capchain *capchain; 1331 uchar_t grpndx; 1332 uint_t ochainndx, nchainndx, bndx; 1333 1334 cap = CAP(ilmp); 1335 capchain = CAPCHAIN(ilmp); 1336 1337 grpndx = (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx]); 1338 1339 /* 1340 * If this symbols capability group is not a lead symbol, then simply 1341 * verify the symbol. 1342 */ 1343 if (grpndx != CAPINFO_SUNW_GLOB) { 1344 Syscapset symcapset = { 0 }; 1345 1346 return (sym_cap_check(cap, grpndx, &symcapset, ilmp, 1347 srp->sr_name, symndx)); 1348 } 1349 1350 /* 1351 * If there is no capabilities chain, return the lead symbol. 1352 */ 1353 if (capchain == NULL) 1354 return (1); 1355 1356 ochainndx = (uint_t)ELF_C_SYM(CAPINFO(ilmp)[symndx]); 1357 1358 /* 1359 * If there is only one member for this family, take it. Once a family 1360 * has been processed, the best family instance is written to the head 1361 * of the chain followed by a null entry. This caching ensures that the 1362 * same family comparison doesn't have to be undertaken more than once. 1363 */ 1364 if (capchain[ochainndx] && (capchain[ochainndx + 1] == 0)) { 1365 Sym *fsym = symtabptr + capchain[ochainndx]; 1366 const char *fname = strtabptr + fsym->st_name; 1367 1368 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, fname, 1369 capchain[ochainndx], M_MACH, NULL)); 1370 1371 srp->sr_sym = fsym; 1372 srp->sr_name = fname; 1373 return (1); 1374 } 1375 1376 /* 1377 * As this symbol is the lead symbol of a capabilities family, it is 1378 * considered the generic member, and therefore forms the basic 1379 * fall-back for the capabilities family. 1380 */ 1381 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_DEFAULT, srp->sr_name, 1382 symndx, M_MACH, NULL)); 1383 bsym = srp->sr_sym; 1384 bname = srp->sr_name; 1385 bndx = symndx; 1386 1387 /* 1388 * Traverse the capabilities chain analyzing each family member. 1389 */ 1390 for (nchainndx = ochainndx + 1, symndx = capchain[nchainndx]; symndx; 1391 nchainndx++, symndx = capchain[nchainndx]) { 1392 Sym *nsym = symtabptr + symndx; 1393 const char *nname = strtabptr + nsym->st_name; 1394 Syscapset symcapset = { 0 }; 1395 1396 if ((grpndx = 1397 (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx])) == 0) 1398 continue; 1399 1400 if (sym_cap_check(cap, grpndx, &symcapset, ilmp, 1401 nname, symndx) == 0) 1402 continue; 1403 1404 /* 1405 * Determine whether a symbol's capabilities are more 1406 * significant than any that have already been validated. 1407 */ 1408 if (is_sym_the_best(&bestcapset, &symcapset)) { 1409 bestcapset = symcapset; 1410 bsym = nsym; 1411 bname = nname; 1412 bndx = symndx; 1413 } 1414 } 1415 1416 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, bname, bndx, 1417 M_MACH, NULL)); 1418 1419 /* 1420 * Having found the best symbol, cache the results by overriding the 1421 * first element of the associated chain. 1422 */ 1423 capchain[ochainndx] = bndx; 1424 capchain[ochainndx + 1] = 0; 1425 1426 /* 1427 * Update the symbol result information for return to the user. 1428 */ 1429 srp->sr_sym = bsym; 1430 srp->sr_name = bname; 1431 return (1); 1432 } 1433