xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/cap.c (revision 7eca354d)
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