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