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