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