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