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.
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.
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]
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
42 * qsort(3c) capability comparison function.
45 compare(const void *vp_a
, const void *vp_b
)
47 Fdesc
*fdp_a
= (Fdesc
*)vp_a
, *fdp_b
= (Fdesc
*)vp_b
;
48 char *strcap_a
, *strcap_b
;
49 Xword hwcap_a
, hwcap_b
;
52 * First, investigate any platform capability.
54 strcap_a
= fdp_a
->fd_scapset
.sc_plat
;
55 strcap_b
= fdp_b
->fd_scapset
.sc_plat
;
57 if (strcap_a
&& (strcap_b
== NULL
))
59 if (strcap_b
&& (strcap_a
== NULL
))
63 * Second, investigate any machine capability.
65 strcap_a
= fdp_a
->fd_scapset
.sc_mach
;
66 strcap_b
= fdp_b
->fd_scapset
.sc_mach
;
68 if (strcap_a
&& (strcap_b
== NULL
))
70 if (strcap_b
&& (strcap_a
== NULL
))
74 * Third, investigate any CA_SUNW_HW_2 hardware capabilities.
76 hwcap_a
= fdp_a
->fd_scapset
.sc_hw_2
;
77 hwcap_b
= fdp_b
->fd_scapset
.sc_hw_2
;
79 if (hwcap_a
> hwcap_b
)
81 if (hwcap_a
< hwcap_b
)
85 * Finally, investigate any CA_SUNW_HW_1 hardware capabilities.
87 hwcap_a
= fdp_a
->fd_scapset
.sc_hw_1
;
88 hwcap_b
= fdp_b
->fd_scapset
.sc_hw_1
;
90 if (hwcap_a
> hwcap_b
)
92 if (hwcap_a
< hwcap_b
)
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
104 DBG_CALL(Dbg_cap_identical(fdp_a
->fd_lml
, fdp_a
->fd_nname
,
107 fdp_a
->fd_flags
|= FLG_FD_IGNORE
;
108 fdp_b
->fd_flags
|= FLG_FD_IGNORE
;
114 * Determine whether HWCAP1 capabilities value is supported.
117 hwcap1_check(Syscapset
*scapset
, Xword val
, Rej_desc
*rej
)
122 * Ensure that the kernel can cope with the required capabilities.
124 if ((rtld_flags2
& RT_FL2_HWCAP
) &&
125 ((mval
= (val
& ~scapset
->sc_hw_1
)) != 0)) {
127 static Conv_cap_val_hw1_buf_t cap_buf
;
129 rej
->rej_type
= SGS_REJ_HWCAP_1
;
130 rej
->rej_str
= conv_cap_val_hw1(mval
,
131 M_MACH
, 0, &cap_buf
);
139 * Determine whether HWCAP2 capabilities value is supported.
142 hwcap2_check(Syscapset
*scapset
, Xword val
, Rej_desc
*rej
)
147 * Ensure that the kernel can cope with the required capabilities.
149 if ((mval
= (val
& ~scapset
->sc_hw_2
)) != 0) {
151 static Conv_cap_val_hw2_buf_t cap_buf
;
153 rej
->rej_type
= SGS_REJ_HWCAP_2
;
154 rej
->rej_str
= conv_cap_val_hw2(mval
,
155 M_MACH
, 0, &cap_buf
);
163 * Process any software capabilities.
167 sfcap1_check(Syscapset
*scapset
, Xword val
, Rej_desc
*rej
)
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.
176 if ((val
& SF1_SUNW_ADDR32
) && ((rtld_flags2
& RT_FL2_ADDR32
) == 0)) {
178 static Conv_cap_val_sf1_buf_t cap_buf
;
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
);
191 * Process any platform capability.
194 platcap_check(Syscapset
*scapset
, const char *str
, Rej_desc
*rej
)
197 * If the platform name hasn't been set, try and obtain it.
199 if ((scapset
->sc_plat
== NULL
) &&
200 (scapset
->sc_platsz
== 0))
201 platform_name(scapset
);
203 if ((scapset
->sc_plat
== NULL
) ||
204 (str
&& strcmp(scapset
->sc_plat
, str
))) {
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.
213 rej
->rej_type
= SGS_REJ_PLATCAP
;
214 rej
->rej_str
= stravl_insert(str
, 0, 0, 0);
222 * Process any machine capability.
225 machcap_check(Syscapset
*scapset
, const char *str
, Rej_desc
*rej
)
228 * If the machine name hasn't been set, try and obtain it.
230 if ((scapset
->sc_mach
== NULL
) &&
231 (scapset
->sc_machsz
== 0))
232 machine_name(scapset
);
234 if ((scapset
->sc_mach
== NULL
) ||
235 (str
&& strcmp(scapset
->sc_mach
, str
))) {
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.
244 rej
->rej_type
= SGS_REJ_MACHCAP
;
245 rej
->rej_str
= stravl_insert(str
, 0, 0, 0);
253 * Generic front-end to capabilities validation.
256 cap_check(Cap
*cptr
, char *strs
, int alt
, Fdesc
*fdp
, Rej_desc
*rej
)
259 int totplat
, ivlplat
, totmach
, ivlmach
;
262 * If the caller has no capabilities, then the object is valid.
268 scapset
= alt_scapset
;
270 scapset
= org_scapset
;
272 totplat
= ivlplat
= totmach
= ivlmach
= 0;
274 while (cptr
->c_tag
!= CA_SUNW_NULL
) {
275 Xword val
= cptr
->c_un
.c_val
;
278 switch (cptr
->c_tag
) {
281 * Remove any historic values that should not be
282 * involved with any validation.
284 val
&= ~AV_HW1_IGNORE
;
286 if (hwcap1_check(scapset
, val
, rej
) == 0)
289 fdp
->fd_scapset
.sc_hw_1
= val
;
292 if (sfcap1_check(scapset
, val
, rej
) == 0)
295 fdp
->fd_scapset
.sc_sf_1
= val
;
298 if (hwcap2_check(scapset
, val
, rej
) == 0)
301 fdp
->fd_scapset
.sc_hw_2
= val
;
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
310 if (totplat
== ivlplat
) {
315 if (platcap_check(scapset
, str
, rej
) == 0)
318 fdp
->fd_scapset
.sc_plat
= str
;
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
328 if (totmach
== ivlmach
) {
333 if (machcap_check(scapset
, str
, rej
) == 0)
336 fdp
->fd_scapset
.sc_mach
= str
;
341 * Capabilities identifiers provide for diagnostics,
342 * but are not attributes that must be compared with
343 * the system. They are ignored.
347 rej
->rej_type
= SGS_REJ_UNKCAP
;
348 rej
->rej_info
= cptr
->c_tag
;
355 * If any platform names, or machine names were found, and all were
356 * invalid, indicate that the object is inappropriate.
358 if ((totplat
&& (totplat
== ivlplat
)) ||
359 (totmach
&& (totmach
== ivlmach
)))
365 #define HWAVL_RECORDED(n) pnavl_recorded(&capavl, n, NULL, NULL)
368 * Determine whether a link-map should use alternative system capabilities.
371 cap_check_lmp_init(Rt_map
*lmp
)
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.
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
388 if ((file
= strrchr(NAME(lmp
), '/')) != NULL
)
393 if ((file
&& (HWAVL_RECORDED(file
) != 0)) ||
394 (HWAVL_RECORDED(NAME(lmp
)) != 0) ||
395 ((PATHNAME(lmp
) != NAME(lmp
)) &&
396 (HWAVL_RECORDED(PATHNAME(lmp
)) != 0)))
403 for (APLIST_TRAVERSE(ALIAS(lmp
), idx
, cp
)) {
404 if ((alt
= HWAVL_RECORDED(cp
)) != 0)
411 * Indicate if this link-map should use alternative system capabilities,
412 * and that the alternative system capabilities check has been carried
415 if ((org_scapset
!= alt_scapset
) && ((capavl
== NULL
) || alt
))
416 FLAGS1(lmp
) |= FL1_RT_ALTCAP
;
417 FLAGS1(lmp
) |= FL1_RT_ALTCHECK
;
421 * Validate the capabilities requirements of a link-map.
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.
427 cap_check_lmp(Rt_map
*lmp
, Rej_desc
*rej
)
429 if ((FLAGS1(lmp
) & FL1_RT_ALTCHECK
) == 0)
430 cap_check_lmp_init(lmp
);
432 return (cap_check(CAP(lmp
), STRTAB(lmp
),
433 (FLAGS1(lmp
) & FL1_RT_ALTCAP
), NULL
, rej
));
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().
443 cap_check_fdesc(Fdesc
*fdp
, Cap
*cptr
, char *strs
, Rej_desc
*rej
)
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.
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
461 ((file
= strrchr(fdp
->fd_oname
, '/')) != NULL
))
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)))
475 * Indicate if this file descriptor should use alternative system
476 * capabilities, and that the alternative system capabilities check has
479 if ((org_scapset
!= alt_scapset
) && ((capavl
== NULL
) || alt
))
480 fdp
->fd_flags
|= FLG_FD_ALTCAP
;
481 fdp
->fd_flags
|= FLG_FD_ALTCHECK
;
484 * Verify that the required capabilities are supported by the reference.
486 return (cap_check(cptr
, strs
, (fdp
->fd_flags
& FLG_FD_ALTCAP
),
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.
496 free_fd(Alist
*fdalp
)
502 for (ALIST_TRAVERSE(fdalp
, idx
, fdp
)) {
504 free((void *)fdp
->fd_oname
);
511 * When $CAPABILITY (or $HWCAP) is used to represent dependencies, take the
512 * associated directory and analyze all the files it contains.
515 cap_dir(Alist
**fdalpp
, Lm_list
*lml
, const char *dname
, Rt_map
*clmp
,
516 uint_t flags
, Rej_desc
*rej
, int *in_nfavl
)
518 char path
[PATH_MAX
], *dst
;
521 struct dirent
*dirent
;
528 * Access the directory in preparation for reading its entries. If
529 * successful, establish the initial pathname.
531 if ((dir
= opendir(dname
)) == NULL
) {
532 Rej_desc _rej
= { 0 };
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
);
542 for (dst
= path
, src
= dname
; *src
; dst
++, src
++)
547 * Read each entry from the directory and determine whether it is a
550 while ((dirent
= readdir(dir
)) != NULL
) {
551 const char *file
= dirent
->d_name
;
554 Rej_desc _rej
= { 0 };
558 * Ignore "." and ".." entries.
560 if ((file
[0] == '.') && ((file
[1] == '\0') ||
561 ((file
[1] == '.') && (file
[2] == '\0'))))
565 * Complete the full pathname.
567 for (_dst
= dst
, src
= file
, file
= dst
; *src
; _dst
++, src
++)
572 * Trace the inspection of this file, and determine any
573 * auditor substitution.
576 pd
.pd_flags
= PD_FLG_PNSLASH
;
578 if (load_trace(lml
, &pd
, clmp
, &fd
) == NULL
)
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.
587 if (find_path(lml
, clmp
, flags
, &fd
, &_rej
, in_nfavl
) == 0) {
588 rejection_inherit(rej
, &_rej
);
592 DBG_CALL(Dbg_cap_candidate(lml
, fd
.fd_nname
));
595 * If this object has already been loaded, save the capabilities
596 * for later sorting. Otherwise we have a new candidate.
599 fd
.fd_scapset
= CAPSET(fd
.fd_lmp
);
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
608 if (((fd
.fd_oname
= strdup(fd
.fd_oname
)) == NULL
) ||
609 (alist_append(&fdalp
, &fd
, sizeof (Fdesc
),
610 AL_CNT_CAP
) == NULL
)) {
615 (void) closedir(dir
);
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.
622 if ((fdalp
== NULL
) || error
) {
629 * Having processed and retained all candidates from this directory,
630 * sort them, based on the precedence of their hardware capabilities.
632 qsort(fdalp
->al_data
, fdalp
->al_nitems
, fdalp
->al_size
, compare
);
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
639 for (ALIST_TRAVERSE(fdalp
, idx
, fdp
)) {
640 if (fdp
->fd_flags
& FLG_FD_IGNORE
)
641 alist_delete(fdalp
, &idx
);
644 if (fdalp
->al_nitems
== 0) {
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
,
661 Lm_list
*lml
= LIST(flmp
);
663 Rej_desc rej
= { 0 };
665 if (cap_dir(&fdalp
, lml
, dir
, flmp
, flags
, &rej
, in_nfavl
) == 0)
669 * Now complete the mapping of each of the ordered objects, adding
670 * each object to a new pathname descriptor.
672 for (ALIST_TRAVERSE(fdalp
, idx
, fdp
)) {
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.
687 DBG_CALL(Dbg_file_filtee(lml
, NAME(flmp
), fdp
->fd_nname
, 0));
689 nlmp
= load_path(lml
, nlmco
, flmp
, mode
,
690 (flags
| FLG_RT_PUBHDL
), &ghp
, fdp
, &rej
, in_nfavl
);
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.
699 if ((pdp
= alist_insert(alpp
, 0, sizeof (Pdesc
),
700 AL_CNT_FILTEES
, ++oidx
)) == NULL
) {
702 remove_lmc(lml
, flmp
, nlmco
, NAME(nlmp
));
706 pdp
->pd_pname
= NAME(nlmp
);
707 pdp
->pd_plen
= strlen(NAME(nlmp
));
710 * Establish the filter handle to prevent any recursion.
713 ghp
->gh_flags
|= GPH_FILTEE
;
714 pdp
->pd_info
= (void *)ghp
;
718 * Audit the filter/filtee established. A return of 0
719 * indicates the auditor wishes to ignore this filtee.
721 if (nlmp
&& (lml
->lm_tflags
| FLAGS1(flmp
)) &
722 LML_TFLG_AUD_OBJFILTER
) {
723 if (audit_objfilter(flmp
, ref
, nlmp
, 0) == 0) {
730 * Finish processing the objects associated with this request.
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)))
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.
743 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD
));
745 (hdl_add(ghp
, flmp
, GPD_FILTER
, NULL
) == NULL
))
749 * If this object is marked an end-filtee, we're done.
751 if (nlmp
&& ghp
&& (FLAGS1(nlmp
) & FL1_RT_ENDFILTE
))
755 * If this filtee loading has failed, generate a diagnostic.
756 * Null out the path name descriptor entry, and continue the
760 DBG_CALL(Dbg_file_filtee(lml
, 0, pdp
->pd_pname
, audit
));
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.
768 if (nlmco
!= ALIST_OFF_DATA
)
769 remove_lmc(lml
, flmp
, nlmco
, pdp
->pd_pname
);
781 * Load an individual capabilities object.
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
)
794 * Obtain the sorted list of hardware capabilities objects available.
796 if (cap_dir(&fdalp
, lml
, dir
, clmp
, flags
, rej
, in_nfavl
) == 0)
800 * From the list of hardware capability objects, use the first and
803 for (ALIST_TRAVERSE(fdalp
, idx
, fdp
)) {
806 if ((found
== 0) && ((lmp
= load_path(lml
, lmco
, clmp
, mode
,
807 flags
, hdl
, &fd
, rej
, in_nfavl
)) != NULL
))
816 * Use a case insensitive string match when looking up capability mask
817 * values by name, and omit the AV_ prefix.
819 #define ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
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.
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.
835 CAP_OVERRIDE
= 0, /* override existing capabilities */
836 CAP_ENABLE
= 1, /* enable capabilities */
837 CAP_DISABLE
= 2 /* disable capabilities */
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 */
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 */
852 cap_modify(Xword tag
, const char *str
)
854 char *caps
, *ptr
, *next
;
855 cap_mode mode
= CAP_OVERRIDE
;
858 if ((caps
= strdup(str
)) == NULL
)
861 for (ptr
= strtok_r(caps
, MSG_ORIG(MSG_CAP_DELIMIT
), &next
);
863 ptr
= strtok_r(NULL
, MSG_ORIG(MSG_CAP_DELIMIT
), &next
)) {
867 * Determine whether this token should be enabled (+),
868 * disabled (-), or override any existing settings.
873 } else if (*ptr
== '-') {
879 * Process the capabilities as directed by the calling tag.
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.
890 if ((val
= (Xword
)elfcap_hw2_from_str(ELFCAP_STYLE
,
891 ptr
, M_MACH
)) != 0) {
895 if ((val
= (Xword
)elfcap_hw1_from_str(ELFCAP_STYLE
,
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.
907 if ((val
= (Xword
)elfcap_sf1_from_str(ELFCAP_STYLE
,
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.
919 * LD_HWCAP=[1]0x40 sets CA_SUNW_HW_1 with 0x40
920 * LD_HWCAP=[2]0x80 sets CA_SUNW_HW_2 with 0x80
922 * Invalid indexes are ignored.
925 if ((*ptr
== '[') && (*(ptr
+ 2) == ']')) {
926 if (*(ptr
+ 1) == '1') {
929 } else if (*(ptr
+ 1) == '2') {
930 if (tag
== CA_SUNW_HW_1
) {
945 if (((val
= strtol(ptr
, NULL
, 16)) == 0) && errno
)
948 cap_settings
[ndx
- 1].cs_val
[mode
] |= val
;
949 cap_settings
[ndx
- 1].cs_set
[mode
]++;
954 * If the "override" token was supplied, set the alternative
955 * system capabilities, then enable or disable others.
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
];
974 * Create an AVL tree of objects that are to be validated against an alternative
975 * system capabilities value.
978 cap_files(const char *str
)
980 char *caps
, *name
, *next
;
982 if ((caps
= strdup(str
)) == NULL
)
985 for (name
= strtok_r(caps
, MSG_ORIG(MSG_CAP_DELIMIT
), &next
);
987 name
= strtok_r(NULL
, MSG_ORIG(MSG_CAP_DELIMIT
), &next
)) {
990 uint_t hash
= sgs_str_hash(name
);
993 * Determine whether this pathname has already been recorded.
995 if (pnavl_recorded(&capavl
, name
, hash
, &where
))
998 if ((pnp
= calloc(sizeof (PathNode
), 1)) != NULL
) {
1000 pnp
->pn_hash
= hash
;
1001 avl_insert(capavl
, pnp
, where
);
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.
1016 cap_alternative(void)
1019 * If no capabilities have been set, we're done.
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
))
1028 * If the user has requested to modify any capabilities, establish a
1029 * unique set from the present system capabilities.
1031 if ((alt_scapset
= malloc(sizeof (Syscapset
))) == NULL
)
1033 *alt_scapset
= *org_scapset
;
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
;
1040 * Process any replaceable variables.
1042 if (rpl_hwcap
&& (cap_modify(CA_SUNW_HW_1
, rpl_hwcap
) == 0))
1044 if (rpl_sfcap
&& (cap_modify(CA_SUNW_SF_1
, rpl_sfcap
) == 0))
1048 alt_scapset
->sc_plat
= (char *)rpl_platcap
;
1049 alt_scapset
->sc_platsz
= strlen(rpl_platcap
);
1052 alt_scapset
->sc_mach
= (char *)rpl_machcap
;
1053 alt_scapset
->sc_machsz
= strlen(rpl_machcap
);
1056 if (rpl_cap_files
&& (cap_files(rpl_cap_files
) == 0))
1060 * Process any permanent variables.
1062 if (prm_hwcap
&& (cap_modify(CA_SUNW_HW_1
, prm_hwcap
) == 0))
1064 if (prm_sfcap
&& (cap_modify(CA_SUNW_SF_1
, prm_sfcap
) == 0))
1068 alt_scapset
->sc_plat
= (char *)prm_platcap
;
1069 alt_scapset
->sc_platsz
= strlen(prm_platcap
);
1072 alt_scapset
->sc_mach
= (char *)prm_machcap
;
1073 alt_scapset
->sc_machsz
= strlen(prm_machcap
);
1076 if (prm_cap_files
&& (cap_files(prm_cap_files
) == 0))
1080 * Reset the replaceable variables. If this is the environment variable
1081 * processing, these variables are now available for configuration file
1084 rpl_hwcap
= rpl_sfcap
= rpl_machcap
= rpl_platcap
=
1085 rpl_cap_files
= NULL
;
1091 * Take the index from a Capinfo entry and determine the associated capabilities
1092 * set. Verify that the capabilities are available for this system.
1095 sym_cap_check(Cap
*cptr
, uint_t cndx
, Syscapset
*bestcapset
, Rt_map
*lmp
,
1096 const char *name
, uint_t ndx
)
1099 int totplat
, ivlplat
, totmach
, ivlmach
, capfail
= 0;
1102 * Determine whether this file requires validation against alternative
1103 * system capabilities.
1105 if ((FLAGS1(lmp
) & FL1_RT_ALTCHECK
) == 0)
1106 cap_check_lmp_init(lmp
);
1108 if (FLAGS1(lmp
) & FL1_RT_ALTCAP
)
1109 scapset
= alt_scapset
;
1111 scapset
= org_scapset
;
1113 totplat
= ivlplat
= totmach
= ivlmach
= 0;
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.
1119 for (cptr
+= cndx
; cptr
->c_tag
!= CA_SUNW_NULL
; cptr
++) {
1120 Xword val
= cptr
->c_un
.c_val
;
1123 switch (cptr
->c_tag
) {
1126 * Remove any historic values that should not be
1127 * involved with any validation.
1129 val
&= ~AV_HW1_IGNORE
;
1131 bestcapset
->sc_hw_1
= val
;
1132 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_HW_1
,
1133 name
, ndx
, M_MACH
, bestcapset
));
1135 if (hwcap1_check(scapset
, val
, NULL
) == 0)
1139 bestcapset
->sc_sf_1
= val
;
1140 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_SF_1
,
1141 name
, ndx
, M_MACH
, bestcapset
));
1143 if (sfcap1_check(scapset
, val
, NULL
) == 0)
1147 bestcapset
->sc_hw_2
= val
;
1148 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_HW_2
,
1149 name
, ndx
, M_MACH
, bestcapset
));
1151 if (hwcap2_check(scapset
, val
, NULL
) == 0)
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.
1160 if (totplat
== ivlplat
) {
1163 str
= STRTAB(lmp
) + val
;
1164 bestcapset
->sc_plat
= str
;
1166 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_PLAT
,
1167 name
, ndx
, M_MACH
, bestcapset
));
1169 if (platcap_check(scapset
, str
, NULL
) == 0)
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.
1179 if (totmach
== ivlmach
) {
1182 str
= STRTAB(lmp
) + val
;
1183 bestcapset
->sc_mach
= str
;
1185 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_MACH
,
1186 name
, ndx
, M_MACH
, bestcapset
));
1188 if (machcap_check(scapset
, str
, NULL
) == 0)
1198 * If any platform definitions, or machine definitions were found, and
1199 * all were invalid, indicate that the object is inappropriate.
1201 if (capfail
|| (totplat
&& (totplat
== ivlplat
)) ||
1202 (totmach
&& (totmach
== ivlmach
))) {
1203 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_REJECTED
, name
, ndx
,
1208 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_CANDIDATE
, name
, ndx
,
1214 * Determine whether a symbols capabilities are more significant than any that
1215 * have already been validated. The precedence of capabilities are:
1217 * PLATCAP -> MACHCAP -> HWCAP_2 -> HWCAP_1
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.
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.
1229 is_sym_the_best(Syscapset
*bestcapset
, Syscapset
*symcapset
)
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.
1238 if (bestcapset
->sc_plat
&& (symcapset
->sc_plat
== NULL
))
1241 if ((bestcapset
->sc_plat
== NULL
) && symcapset
->sc_plat
)
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.
1251 if (bestcapset
->sc_mach
&& (symcapset
->sc_mach
== NULL
))
1254 if ((bestcapset
->sc_mach
== NULL
) && symcapset
->sc_mach
)
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.
1264 if (bestcapset
->sc_hw_2
> symcapset
->sc_hw_2
)
1267 if (bestcapset
->sc_hw_2
< symcapset
->sc_hw_2
)
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.
1277 if (bestcapset
->sc_hw_1
> symcapset
->sc_hw_1
)
1280 if (bestcapset
->sc_hw_1
< symcapset
->sc_hw_1
)
1284 * Both capabilities are the same. Retain the best on a first-come
1285 * first-served basis.
1291 * Initiate symbol capabilities processing. If an initial symbol lookup
1292 * results in binding to a symbol that has an associated SUNW_capinfo entry,
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
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.
1309 cap_match(Sresult
*srp
, uint_t symndx
, Sym
*symtabptr
, char *strtabptr
)
1311 Rt_map
*ilmp
= srp
->sr_dmap
;
1314 Syscapset bestcapset
= { 0 };
1318 uint_t ochainndx
, nchainndx
, bndx
;
1321 capchain
= CAPCHAIN(ilmp
);
1323 grpndx
= (uchar_t
)ELF_C_GROUP(CAPINFO(ilmp
)[symndx
]);
1326 * If this symbols capability group is not a lead symbol, then simply
1327 * verify the symbol.
1329 if (grpndx
!= CAPINFO_SUNW_GLOB
) {
1330 Syscapset symcapset
= { 0 };
1332 return (sym_cap_check(cap
, grpndx
, &symcapset
, ilmp
,
1333 srp
->sr_name
, symndx
));
1337 * If there is no capabilities chain, return the lead symbol.
1339 if (capchain
== NULL
)
1342 ochainndx
= (uint_t
)ELF_C_SYM(CAPINFO(ilmp
)[symndx
]);
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.
1350 if (capchain
[ochainndx
] && (capchain
[ochainndx
+ 1] == 0)) {
1351 Sym
*fsym
= symtabptr
+ capchain
[ochainndx
];
1352 const char *fname
= strtabptr
+ fsym
->st_name
;
1354 DBG_CALL(Dbg_syms_cap_lookup(ilmp
, DBG_CAP_USED
, fname
,
1355 capchain
[ochainndx
], M_MACH
, NULL
));
1358 srp
->sr_name
= fname
;
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.
1367 DBG_CALL(Dbg_syms_cap_lookup(ilmp
, DBG_CAP_DEFAULT
, srp
->sr_name
,
1368 symndx
, M_MACH
, NULL
));
1370 bname
= srp
->sr_name
;
1374 * Traverse the capabilities chain analyzing each family member.
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 };
1383 (uchar_t
)ELF_C_GROUP(CAPINFO(ilmp
)[symndx
])) == 0)
1386 if (sym_cap_check(cap
, grpndx
, &symcapset
, ilmp
,
1387 nname
, symndx
) == 0)
1391 * Determine whether a symbol's capabilities are more
1392 * significant than any that have already been validated.
1394 if (is_sym_the_best(&bestcapset
, &symcapset
)) {
1395 bestcapset
= symcapset
;
1402 DBG_CALL(Dbg_syms_cap_lookup(ilmp
, DBG_CAP_USED
, bname
, bndx
,
1406 * Having found the best symbol, cache the results by overriding the
1407 * first element of the associated chain.
1409 capchain
[ochainndx
] = bndx
;
1410 capchain
[ochainndx
+ 1] = 0;
1413 * Update the symbol result information for return to the user.
1416 srp
->sr_name
= bname
;