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