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