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