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, 0, 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.
927 if ((*ptr
== '[') && (*(ptr
+ 2) == ']')) {
928 if (*(ptr
+ 1) == '1') {
931 } else if (*(ptr
+ 1) == '2') {
932 if (tag
== CA_SUNW_HW_1
) {
947 if (((val
= strtol(ptr
, &end
, 16)) == 0) && errno
)
951 * If the value wasn't an entirely valid hexadecimal
952 * integer, assume it was intended as a capability
956 eprintf(NULL
, ERR_WARNING
,
957 MSG_INTL(MSG_CAP_IGN_UNKCAP
), ptr
);
962 cap_settings
[ndx
- 1].cs_val
[mode
] |= val
;
963 cap_settings
[ndx
- 1].cs_set
[mode
]++;
968 * If the "override" token was supplied, set the alternative
969 * system capabilities, then enable or disable others.
971 for (ndx
= 0; ndx
< CA_SUNW_HW_2
; ndx
++) {
972 if (cap_settings
[ndx
].cs_set
[CAP_OVERRIDE
])
973 *(cap_settings
[ndx
].cs_aval
) =
974 cap_settings
[ndx
].cs_val
[CAP_OVERRIDE
];
975 if (cap_settings
[ndx
].cs_set
[CAP_ENABLE
])
976 *(cap_settings
[ndx
].cs_aval
) |=
977 cap_settings
[ndx
].cs_val
[CAP_ENABLE
];
978 if (cap_settings
[ndx
].cs_set
[CAP_DISABLE
])
979 *(cap_settings
[ndx
].cs_aval
) &=
980 ~cap_settings
[ndx
].cs_val
[CAP_DISABLE
];
988 * Create an AVL tree of objects that are to be validated against an alternative
989 * system capabilities value.
992 cap_files(const char *str
)
994 char *caps
, *name
, *next
;
996 if ((caps
= strdup(str
)) == NULL
)
999 for (name
= strtok_r(caps
, MSG_ORIG(MSG_CAP_DELIMIT
), &next
);
1001 name
= strtok_r(NULL
, MSG_ORIG(MSG_CAP_DELIMIT
), &next
)) {
1004 uint_t hash
= sgs_str_hash(name
);
1007 * Determine whether this pathname has already been recorded.
1009 if (pnavl_recorded(&capavl
, name
, hash
, &where
))
1012 if ((pnp
= calloc(sizeof (PathNode
), 1)) != NULL
) {
1013 pnp
->pn_name
= name
;
1014 pnp
->pn_hash
= hash
;
1015 avl_insert(capavl
, pnp
, where
);
1023 * Set alternative system capabilities. A user can establish alternative system
1024 * capabilities from the environment, or from a configuration file. This
1025 * routine is called in each instance. Environment variables only set the
1026 * replaceable (rpl) variables. Configuration files can set both replaceable
1027 * (rpl) and permanent (prm) variables.
1030 cap_alternative(void)
1033 * If no capabilities have been set, we're done.
1035 if ((rpl_hwcap
== NULL
) && (rpl_sfcap
== NULL
) &&
1036 (rpl_machcap
== NULL
) && (rpl_platcap
== NULL
) &&
1037 (prm_hwcap
== NULL
) && (prm_sfcap
== NULL
) &&
1038 (prm_machcap
== NULL
) && (prm_platcap
== NULL
))
1042 * If the user has requested to modify any capabilities, establish a
1043 * unique set from the present system capabilities.
1045 if ((alt_scapset
= malloc(sizeof (Syscapset
))) == NULL
)
1047 *alt_scapset
= *org_scapset
;
1049 cap_settings
[CA_SUNW_HW_1
- 1].cs_aval
= &alt_scapset
->sc_hw_1
;
1050 cap_settings
[CA_SUNW_SF_1
- 1].cs_aval
= &alt_scapset
->sc_sf_1
;
1051 cap_settings
[CA_SUNW_HW_2
- 1].cs_aval
= &alt_scapset
->sc_hw_2
;
1054 * Process any replaceable variables.
1056 if (rpl_hwcap
&& (cap_modify(CA_SUNW_HW_1
, rpl_hwcap
) == 0))
1058 if (rpl_sfcap
&& (cap_modify(CA_SUNW_SF_1
, rpl_sfcap
) == 0))
1062 alt_scapset
->sc_plat
= (char *)rpl_platcap
;
1063 alt_scapset
->sc_platsz
= strlen(rpl_platcap
);
1066 alt_scapset
->sc_mach
= (char *)rpl_machcap
;
1067 alt_scapset
->sc_machsz
= strlen(rpl_machcap
);
1070 if (rpl_cap_files
&& (cap_files(rpl_cap_files
) == 0))
1074 * Process any permanent variables.
1076 if (prm_hwcap
&& (cap_modify(CA_SUNW_HW_1
, prm_hwcap
) == 0))
1078 if (prm_sfcap
&& (cap_modify(CA_SUNW_SF_1
, prm_sfcap
) == 0))
1082 alt_scapset
->sc_plat
= (char *)prm_platcap
;
1083 alt_scapset
->sc_platsz
= strlen(prm_platcap
);
1086 alt_scapset
->sc_mach
= (char *)prm_machcap
;
1087 alt_scapset
->sc_machsz
= strlen(prm_machcap
);
1090 if (prm_cap_files
&& (cap_files(prm_cap_files
) == 0))
1094 * Reset the replaceable variables. If this is the environment variable
1095 * processing, these variables are now available for configuration file
1098 rpl_hwcap
= rpl_sfcap
= rpl_machcap
= rpl_platcap
=
1099 rpl_cap_files
= NULL
;
1105 * Take the index from a Capinfo entry and determine the associated capabilities
1106 * set. Verify that the capabilities are available for this system.
1109 sym_cap_check(Cap
*cptr
, uint_t cndx
, Syscapset
*bestcapset
, Rt_map
*lmp
,
1110 const char *name
, uint_t ndx
)
1113 int totplat
, ivlplat
, totmach
, ivlmach
, capfail
= 0;
1116 * Determine whether this file requires validation against alternative
1117 * system capabilities.
1119 if ((FLAGS1(lmp
) & FL1_RT_ALTCHECK
) == 0)
1120 cap_check_lmp_init(lmp
);
1122 if (FLAGS1(lmp
) & FL1_RT_ALTCAP
)
1123 scapset
= alt_scapset
;
1125 scapset
= org_scapset
;
1127 totplat
= ivlplat
= totmach
= ivlmach
= 0;
1130 * A capabilities index points to a capabilities group that can consist
1131 * of one or more capabilities, terminated with a CA_SUNW_NULL entry.
1133 for (cptr
+= cndx
; cptr
->c_tag
!= CA_SUNW_NULL
; cptr
++) {
1134 Xword val
= cptr
->c_un
.c_val
;
1137 switch (cptr
->c_tag
) {
1140 * Remove any historic values that should not be
1141 * involved with any validation.
1143 val
&= ~AV_HW1_IGNORE
;
1145 bestcapset
->sc_hw_1
= val
;
1146 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_HW_1
,
1147 name
, ndx
, M_MACH
, bestcapset
));
1149 if (hwcap1_check(scapset
, val
, NULL
) == 0)
1153 bestcapset
->sc_sf_1
= val
;
1154 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_SF_1
,
1155 name
, ndx
, M_MACH
, bestcapset
));
1157 if (sfcap1_check(scapset
, val
, NULL
) == 0)
1161 bestcapset
->sc_hw_2
= val
;
1162 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_HW_2
,
1163 name
, ndx
, M_MACH
, bestcapset
));
1165 if (hwcap2_check(scapset
, val
, NULL
) == 0)
1170 * A capabilities set can define multiple platform names
1171 * that are appropriate. Only if all the names are
1172 * deemed invalid is the group determined inappropriate.
1174 if (totplat
== ivlplat
) {
1177 str
= STRTAB(lmp
) + val
;
1178 bestcapset
->sc_plat
= str
;
1180 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_PLAT
,
1181 name
, ndx
, M_MACH
, bestcapset
));
1183 if (platcap_check(scapset
, str
, NULL
) == 0)
1189 * A capabilities set can define multiple machine names
1190 * that are appropriate. Only if all the names are
1191 * deemed invalid is the group determined inappropriate.
1193 if (totmach
== ivlmach
) {
1196 str
= STRTAB(lmp
) + val
;
1197 bestcapset
->sc_mach
= str
;
1199 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_MACH
,
1200 name
, ndx
, M_MACH
, bestcapset
));
1202 if (machcap_check(scapset
, str
, NULL
) == 0)
1212 * If any platform definitions, or machine definitions were found, and
1213 * all were invalid, indicate that the object is inappropriate.
1215 if (capfail
|| (totplat
&& (totplat
== ivlplat
)) ||
1216 (totmach
&& (totmach
== ivlmach
))) {
1217 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_REJECTED
, name
, ndx
,
1222 DBG_CALL(Dbg_syms_cap_lookup(lmp
, DBG_CAP_CANDIDATE
, name
, ndx
,
1228 * Determine whether a symbols capabilities are more significant than any that
1229 * have already been validated. The precedence of capabilities are:
1231 * PLATCAP -> MACHCAP -> HWCAP_2 -> HWCAP_1
1234 * Presently we make no comparisons of software capabilities. However, should
1235 * this symbol capability have required the SF1_SUNW_ADDR32 attribute, then
1236 * this would have been validated as appropriate or not.
1238 * bestcapset is the presently available 'best' capabilities group, and
1239 * symcapset is the present capabilities group under investigation. Return 0
1240 * if the bestcapset should remain in affect, or 1 if the symcapset is better.
1243 is_sym_the_best(Syscapset
*bestcapset
, Syscapset
*symcapset
)
1246 * Check any platform capability. If the new symbol isn't associated
1247 * with a CA_SUNW_PLAT capability, and the best symbol is, then retain
1248 * the best capabilities group. If the new symbol is associated with a
1249 * CA_SUNW_PLAT capability, and the best symbol isn't, then the new
1250 * symbol needs to be taken.
1252 if (bestcapset
->sc_plat
&& (symcapset
->sc_plat
== NULL
))
1255 if ((bestcapset
->sc_plat
== NULL
) && symcapset
->sc_plat
)
1259 * Check any machine name capability. If the new symbol isn't
1260 * associated with a CA_SUNW_MACH capability, and the best symbol is,
1261 * then retain the best capabilities group. If the new symbol is
1262 * associated with a CA_SUNW_MACH capability, and the best symbol isn't,
1263 * then the new symbol needs to be taken.
1265 if (bestcapset
->sc_mach
&& (symcapset
->sc_mach
== NULL
))
1268 if ((bestcapset
->sc_mach
== NULL
) && symcapset
->sc_mach
)
1272 * Check the hardware capabilities. If the best symbols CA_SUNW_HW_2
1273 * capabilities are greater than the new symbols capabilities, then
1274 * retain the best capabilities group. If the new symbols CA_SUNW_HW_2
1275 * capabilities are greater than the best symbol, then the new symbol
1276 * needs to be taken.
1278 if (bestcapset
->sc_hw_2
> symcapset
->sc_hw_2
)
1281 if (bestcapset
->sc_hw_2
< symcapset
->sc_hw_2
)
1285 * Check the remaining hardware capabilities. If the best symbols
1286 * CA_SUNW_HW_1 capabilities are greater than the new symbols
1287 * capabilities, then retain the best capabilities group. If the new
1288 * symbols CA_SUNW_HW_1 capabilities are greater than the best symbol,
1289 * then the new symbol needs to be taken.
1291 if (bestcapset
->sc_hw_1
> symcapset
->sc_hw_1
)
1294 if (bestcapset
->sc_hw_1
< symcapset
->sc_hw_1
)
1298 * Both capabilities are the same. Retain the best on a first-come
1299 * first-served basis.
1305 * Initiate symbol capabilities processing. If an initial symbol lookup
1306 * results in binding to a symbol that has an associated SUNW_capinfo entry,
1309 * The standard model is that this initial symbol is the lead capabilities
1310 * symbol (defined as CAPINFO_SUNW_GLOB) of a capabilities family. This lead
1311 * symbol's SUNW_capinfo information points to the SUNW_capchain entry that
1312 * provides the family symbol indexes. We traverse this chain, looking at
1313 * each family member, to discover the best capabilities instance. This
1314 * instance name and symbol information is returned to establish the final
1317 * If the symbol that got us here is not CAPINFO_SUNW_GLOB, then we've bound
1318 * directly to a capabilities symbol which must be verified. This is not the
1319 * model created by ld(1) using -z symbolcap, but might be created directly
1320 * within a relocatable object by the compilation system.
1323 cap_match(Sresult
*srp
, uint_t symndx
, Sym
*symtabptr
, char *strtabptr
)
1325 Rt_map
*ilmp
= srp
->sr_dmap
;
1328 Syscapset bestcapset
= { 0 };
1332 uint_t ochainndx
, nchainndx
, bndx
;
1335 capchain
= CAPCHAIN(ilmp
);
1337 grpndx
= (uchar_t
)ELF_C_GROUP(CAPINFO(ilmp
)[symndx
]);
1340 * If this symbols capability group is not a lead symbol, then simply
1341 * verify the symbol.
1343 if (grpndx
!= CAPINFO_SUNW_GLOB
) {
1344 Syscapset symcapset
= { 0 };
1346 return (sym_cap_check(cap
, grpndx
, &symcapset
, ilmp
,
1347 srp
->sr_name
, symndx
));
1351 * If there is no capabilities chain, return the lead symbol.
1353 if (capchain
== NULL
)
1356 ochainndx
= (uint_t
)ELF_C_SYM(CAPINFO(ilmp
)[symndx
]);
1359 * If there is only one member for this family, take it. Once a family
1360 * has been processed, the best family instance is written to the head
1361 * of the chain followed by a null entry. This caching ensures that the
1362 * same family comparison doesn't have to be undertaken more than once.
1364 if (capchain
[ochainndx
] && (capchain
[ochainndx
+ 1] == 0)) {
1365 Sym
*fsym
= symtabptr
+ capchain
[ochainndx
];
1366 const char *fname
= strtabptr
+ fsym
->st_name
;
1368 DBG_CALL(Dbg_syms_cap_lookup(ilmp
, DBG_CAP_USED
, fname
,
1369 capchain
[ochainndx
], M_MACH
, NULL
));
1372 srp
->sr_name
= fname
;
1377 * As this symbol is the lead symbol of a capabilities family, it is
1378 * considered the generic member, and therefore forms the basic
1379 * fall-back for the capabilities family.
1381 DBG_CALL(Dbg_syms_cap_lookup(ilmp
, DBG_CAP_DEFAULT
, srp
->sr_name
,
1382 symndx
, M_MACH
, NULL
));
1384 bname
= srp
->sr_name
;
1388 * Traverse the capabilities chain analyzing each family member.
1390 for (nchainndx
= ochainndx
+ 1, symndx
= capchain
[nchainndx
]; symndx
;
1391 nchainndx
++, symndx
= capchain
[nchainndx
]) {
1392 Sym
*nsym
= symtabptr
+ symndx
;
1393 const char *nname
= strtabptr
+ nsym
->st_name
;
1394 Syscapset symcapset
= { 0 };
1397 (uchar_t
)ELF_C_GROUP(CAPINFO(ilmp
)[symndx
])) == 0)
1400 if (sym_cap_check(cap
, grpndx
, &symcapset
, ilmp
,
1401 nname
, symndx
) == 0)
1405 * Determine whether a symbol's capabilities are more
1406 * significant than any that have already been validated.
1408 if (is_sym_the_best(&bestcapset
, &symcapset
)) {
1409 bestcapset
= symcapset
;
1416 DBG_CALL(Dbg_syms_cap_lookup(ilmp
, DBG_CAP_USED
, bname
, bndx
,
1420 * Having found the best symbol, cache the results by overriding the
1421 * first element of the associated chain.
1423 capchain
[ochainndx
] = bndx
;
1424 capchain
[ochainndx
+ 1] = 0;
1427 * Update the symbol result information for return to the user.
1430 srp
->sr_name
= bname
;