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