xref: /onnv-gate/usr/src/cmd/sgs/crle/common/depend.c (revision 9131:d7741cc87056)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51976Sab196087  * Common Development and Distribution License (the "License").
61976Sab196087  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9131SRod.Evans@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include	<sys/types.h>
270Sstevel@tonic-gate #include	<stdio.h>
280Sstevel@tonic-gate #include	<errno.h>
290Sstevel@tonic-gate #include	<unistd.h>
300Sstevel@tonic-gate #include	<string.h>
310Sstevel@tonic-gate #include	<wait.h>
320Sstevel@tonic-gate #include	<limits.h>
330Sstevel@tonic-gate #include	<gelf.h>
340Sstevel@tonic-gate #include	"machdep.h"
350Sstevel@tonic-gate #include	"sgs.h"
360Sstevel@tonic-gate #include	"conv.h"
370Sstevel@tonic-gate #include	"_crle.h"
380Sstevel@tonic-gate #include	"msg.h"
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * Establish an association between a filter and filtee.  Both the filter and
420Sstevel@tonic-gate  * filtee already exist in the internal hash table, since auditing registers
430Sstevel@tonic-gate  * objects (la_objopen()) before it registers filters (la_objfilter()).
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate static int
filter(Crle_desc * crle,const char * filter,const char * str,const char * filtee)460Sstevel@tonic-gate filter(Crle_desc *crle, const char *filter, const char *str, const char *filtee)
470Sstevel@tonic-gate {
48*9131SRod.Evans@Sun.COM 	Hash_ent	*fltrent, *flteent;
49*9131SRod.Evans@Sun.COM 	Flt_desc	*flt;
50*9131SRod.Evans@Sun.COM 	Aliste		idx;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	/*
530Sstevel@tonic-gate 	 * Locate the filter.  Mark the underlying object as the filter to
540Sstevel@tonic-gate 	 * reflect that no matter how it is referenced, it's a filter.
550Sstevel@tonic-gate 	 */
560Sstevel@tonic-gate 	if ((fltrent = get_hash(crle->c_strtbl, (Addr)filter, 0,
57*9131SRod.Evans@Sun.COM 	    HASH_FND_ENT)) == NULL)
580Sstevel@tonic-gate 		return (1);
590Sstevel@tonic-gate 	if ((fltrent = get_hash(crle->c_strtbl, (Addr)fltrent->e_obj->o_path, 0,
60*9131SRod.Evans@Sun.COM 	    HASH_FND_ENT)) == NULL)
610Sstevel@tonic-gate 		return (1);
620Sstevel@tonic-gate 	fltrent->e_obj->o_flags |= RTC_OBJ_FILTER;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	/*
650Sstevel@tonic-gate 	 * Locate the filtee.  Mark the referencing object as the filtee, as
660Sstevel@tonic-gate 	 * this is the object referenced by the filter.
670Sstevel@tonic-gate 	 */
680Sstevel@tonic-gate 	if ((flteent = get_hash(crle->c_strtbl, (Addr)filtee, 0,
69*9131SRod.Evans@Sun.COM 	    HASH_FND_ENT)) == NULL)
700Sstevel@tonic-gate 		return (1);
710Sstevel@tonic-gate 	flteent->e_flags |= RTC_OBJ_FILTEE;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	/*
740Sstevel@tonic-gate 	 * Traverse the filter list using the filters real name.  If ld.so.1
750Sstevel@tonic-gate 	 * inspects the resulting configuration file for filters, it's the
760Sstevel@tonic-gate 	 * objects real name that will be used (PATHNAME()).
770Sstevel@tonic-gate 	 */
78*9131SRod.Evans@Sun.COM 	for (APLIST_TRAVERSE(crle->c_flt, idx, flt)) {
790Sstevel@tonic-gate 		/*
800Sstevel@tonic-gate 		 * Determine whether this filter and filtee string pair already
810Sstevel@tonic-gate 		 * exist.
820Sstevel@tonic-gate 		 */
830Sstevel@tonic-gate 		if ((strcmp(flt->f_fent->e_obj->o_path,
840Sstevel@tonic-gate 		    fltrent->e_obj->o_path) != 0) &&
850Sstevel@tonic-gate 		    (strcmp(flt->f_str, str) != 0))
860Sstevel@tonic-gate 			continue;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 		/*
890Sstevel@tonic-gate 		 * Add this filtee additional association.
900Sstevel@tonic-gate 		 */
91*9131SRod.Evans@Sun.COM 		if (aplist_append(&(flt->f_filtee), flteent,
92*9131SRod.Evans@Sun.COM 		    AL_CNT_CRLE) == NULL)
930Sstevel@tonic-gate 			return (1);
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 		crle->c_fltenum++;
960Sstevel@tonic-gate 		return (0);
970Sstevel@tonic-gate 	}
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	/*
1000Sstevel@tonic-gate 	 * This is a new filter descriptor.  Add this new filtee association.
1010Sstevel@tonic-gate 	 */
102*9131SRod.Evans@Sun.COM 	if (((flt = malloc(sizeof (Flt_desc))) == NULL) ||
1030Sstevel@tonic-gate 	    ((flt->f_strsz = strlen(str) + 1) == 0) ||
104*9131SRod.Evans@Sun.COM 	    ((flt->f_str = malloc(flt->f_strsz)) == NULL)) {
1050Sstevel@tonic-gate 		int err = errno;
1060Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
1070Sstevel@tonic-gate 		    crle->c_name, strerror(err));
1080Sstevel@tonic-gate 		return (1);
1090Sstevel@tonic-gate 	}
110*9131SRod.Evans@Sun.COM 	if ((aplist_append(&(crle->c_flt), flt, AL_CNT_CRLE) == NULL) ||
111*9131SRod.Evans@Sun.COM 	    (aplist_append(&(flt->f_filtee), flteent, AL_CNT_CRLE) == NULL))
1120Sstevel@tonic-gate 		return (1);
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	flt->f_fent = fltrent;
1150Sstevel@tonic-gate 	(void) memcpy((void *)flt->f_str, (void *)str, flt->f_strsz);
1160Sstevel@tonic-gate 	crle->c_strsize += flt->f_strsz;
1170Sstevel@tonic-gate 	crle->c_fltrnum += 1;
1180Sstevel@tonic-gate 	crle->c_fltenum += 2;		/* Account for null filtee desc. */
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	return (0);
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate  * Establish the dependencies of an ELF object and add them to the internal
1250Sstevel@tonic-gate  * configuration information. This information is gathered by using libcrle.so.1
1260Sstevel@tonic-gate  * as an audit library - this is akin to using ldd(1) only simpler.
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate int
depend(Crle_desc * crle,const char * name,Half flags,GElf_Ehdr * ehdr)1290Sstevel@tonic-gate depend(Crle_desc *crle, const char *name, Half flags, GElf_Ehdr *ehdr)
1300Sstevel@tonic-gate {
1310Sstevel@tonic-gate 	const char	*exename;
1320Sstevel@tonic-gate 	const char	*preload;
1330Sstevel@tonic-gate 	int		fildes[2], pid;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	/*
1360Sstevel@tonic-gate 	 * If we're dealing with a dynamic executable we'll execute it,
1370Sstevel@tonic-gate 	 * otherwise we'll preload the shared object with one of the lddstub's.
1380Sstevel@tonic-gate 	 */
1390Sstevel@tonic-gate 	if (ehdr->e_type == ET_EXEC) {
1400Sstevel@tonic-gate 		exename = name;
141*9131SRod.Evans@Sun.COM 		preload = NULL;
1420Sstevel@tonic-gate 	} else {
1431976Sab196087 		exename = conv_lddstub(M_CLASS);
1440Sstevel@tonic-gate 		preload = name;
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/*
1480Sstevel@tonic-gate 	 * Set up a pipe through which the audit library will write the
1490Sstevel@tonic-gate 	 * dependencies.
1500Sstevel@tonic-gate 	 */
1510Sstevel@tonic-gate 	if (pipe(fildes) == -1) {
1520Sstevel@tonic-gate 		int err = errno;
1530Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_PIPE),
1540Sstevel@tonic-gate 		    crle->c_name, strerror(err));
1550Sstevel@tonic-gate 		return (1);
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/*
1590Sstevel@tonic-gate 	 * Fork ourselves to run our executable and collect its dependencies.
1600Sstevel@tonic-gate 	 */
1610Sstevel@tonic-gate 	if ((pid = fork()) == -1) {
1620Sstevel@tonic-gate 		int err = errno;
1630Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK),
1640Sstevel@tonic-gate 		    crle->c_name, strerror(err));
1650Sstevel@tonic-gate 		return (1);
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	if (pid) {
1690Sstevel@tonic-gate 		/*
1700Sstevel@tonic-gate 		 * Parent. Read each dependency from the audit library. The read
1710Sstevel@tonic-gate 		 * side of the pipe is attached to stdio to make obtaining the
1720Sstevel@tonic-gate 		 * individual dependencies easier.
1730Sstevel@tonic-gate 		 */
1740Sstevel@tonic-gate 		int	error = 0, status;
1750Sstevel@tonic-gate 		FILE	*fd;
1760Sstevel@tonic-gate 		char	buffer[PATH_MAX];
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 		(void) close(fildes[1]);
1790Sstevel@tonic-gate 		if ((fd = fdopen(fildes[0], MSG_ORIG(MSG_STR_READ))) != NULL) {
1800Sstevel@tonic-gate 			char	*str;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 			while (fgets(buffer, PATH_MAX, fd) != NULL) {
1830Sstevel@tonic-gate 				/*
1840Sstevel@tonic-gate 				 * Make sure we recognize the message, remove
1850Sstevel@tonic-gate 				 * the newline (which allowed fgets() use) and
1860Sstevel@tonic-gate 				 * register the name;
1870Sstevel@tonic-gate 				 */
1880Sstevel@tonic-gate 				if (strncmp(MSG_ORIG(MSG_AUD_PRF), buffer,
1890Sstevel@tonic-gate 				    MSG_AUD_PRF_SIZE))
1900Sstevel@tonic-gate 					continue;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 				str = strrchr(buffer, '\n');
1930Sstevel@tonic-gate 				*str = '\0';
1940Sstevel@tonic-gate 				str = buffer + MSG_AUD_PRF_SIZE;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 				if (strncmp(MSG_ORIG(MSG_AUD_DEPEND),
1970Sstevel@tonic-gate 				    str, MSG_AUD_DEPEND_SIZE) == 0) {
1980Sstevel@tonic-gate 					/*
1990Sstevel@tonic-gate 					 * Process any dependencies.
2000Sstevel@tonic-gate 					 */
2010Sstevel@tonic-gate 					str += MSG_AUD_DEPEND_SIZE;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 					if ((error = inspect(crle, str,
2040Sstevel@tonic-gate 					    (flags & ~RTC_OBJ_GROUP))) != 0)
2050Sstevel@tonic-gate 						break;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 				} else if (strncmp(MSG_ORIG(MSG_AUD_FILTER),
2080Sstevel@tonic-gate 				    str, MSG_AUD_FILTER_SIZE) == 0) {
2090Sstevel@tonic-gate 					char	*_flt, *_str;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 					/*
2120Sstevel@tonic-gate 					 * Process any filters.
2130Sstevel@tonic-gate 					 */
2140Sstevel@tonic-gate 					_flt = str += MSG_AUD_FILTER_SIZE;
2150Sstevel@tonic-gate 					_str = strchr(str, ':');
2160Sstevel@tonic-gate 					*_str++ = '\0'; str = _str++;
2170Sstevel@tonic-gate 					str = strrchr(str, ')');
2180Sstevel@tonic-gate 					*str++ = '\0'; str++;
2190Sstevel@tonic-gate 					if ((error = filter(crle, _flt, _str,
2200Sstevel@tonic-gate 					    str)) != 0)
2210Sstevel@tonic-gate 						break;
2220Sstevel@tonic-gate 				}
2230Sstevel@tonic-gate 			}
2240Sstevel@tonic-gate 		} else
2250Sstevel@tonic-gate 			error = errno;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		while (wait(&status) != pid)
2280Sstevel@tonic-gate 			;
2290Sstevel@tonic-gate 		if (status) {
2300Sstevel@tonic-gate 			if (WIFSIGNALED(status)) {
2310Sstevel@tonic-gate 				(void) fprintf(stderr,
2320Sstevel@tonic-gate 				    MSG_INTL(MSG_SYS_EXEC), crle->c_name,
2330Sstevel@tonic-gate 				    exename, (WSIGMASK & status),
2340Sstevel@tonic-gate 				    ((status & WCOREFLG) ?
2350Sstevel@tonic-gate 				    MSG_INTL(MSG_SYS_CORE) :
2360Sstevel@tonic-gate 				    MSG_ORIG(MSG_STR_EMPTY)));
2370Sstevel@tonic-gate 			}
2380Sstevel@tonic-gate 			error = status;
2390Sstevel@tonic-gate 		}
2400Sstevel@tonic-gate 		(void) fclose(fd);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		return (error);
2430Sstevel@tonic-gate 	} else {
2440Sstevel@tonic-gate 		char	efds[MSG_ENV_AUD_FD_SIZE + 10];
2450Sstevel@tonic-gate 		char	epld[PATH_MAX];
2460Sstevel@tonic-gate 		char	eldf[PATH_MAX];
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		(void) close(fildes[0]);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		/*
2510Sstevel@tonic-gate 		 * Child. Set up environment variables to enable and identify
2520Sstevel@tonic-gate 		 * auditing.  Initialize CRLE_FD and LD_FLAGS strings.
2530Sstevel@tonic-gate 		 */
2540Sstevel@tonic-gate 		(void) snprintf(efds, (MSG_ENV_AUD_FD_SIZE + 10),
2550Sstevel@tonic-gate 		    MSG_ORIG(MSG_ENV_AUD_FD), fildes[1]);
2560Sstevel@tonic-gate 		(void) snprintf(eldf, PATH_MAX, MSG_ORIG(MSG_ENV_LD_FLAGS));
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 		/*
2590Sstevel@tonic-gate 		 * If asked to dump a group of dependencies make sure any
2600Sstevel@tonic-gate 		 * lazily-loaded objects get processed - (append loadavail to
2610Sstevel@tonic-gate 		 * LD_FLAGS=confgen).
2620Sstevel@tonic-gate 		 */
2630Sstevel@tonic-gate 		if (flags & RTC_OBJ_GROUP)
2640Sstevel@tonic-gate 			(void) strcat(eldf, MSG_ORIG(MSG_LDFLG_LOADAVAIL));
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 		/*
2670Sstevel@tonic-gate 		 * Put LD_PRELOAD= in the environment if necessary.
2680Sstevel@tonic-gate 		 */
2690Sstevel@tonic-gate 		if (preload) {
2700Sstevel@tonic-gate 			(void) snprintf(epld, PATH_MAX,
2710Sstevel@tonic-gate 			    MSG_ORIG(MSG_ENV_LD_PRELOAD), preload);
2720Sstevel@tonic-gate 		}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		/*
2750Sstevel@tonic-gate 		 * Put strings in the environment for exec().
2760Sstevel@tonic-gate 		 * NOTE, use of automatic variables for construction of the
2770Sstevel@tonic-gate 		 * environment variables is legitimate here, as they are local
2780Sstevel@tonic-gate 		 * to the child process and are established solely for exec().
2790Sstevel@tonic-gate 		 */
2800Sstevel@tonic-gate 		if ((putenv(efds) != 0) || (putenv(crle->c_audit) != 0) ||
2810Sstevel@tonic-gate 		    (putenv(eldf) != 0) || (preload && (putenv(epld) != 0))) {
2820Sstevel@tonic-gate 			int err = errno;
2830Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_PUTENV),
2840Sstevel@tonic-gate 			    crle->c_name, strerror(err));
2850Sstevel@tonic-gate 			return (1);
2860Sstevel@tonic-gate 		}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 		if (execlp(exename, exename, 0) == -1) {
2890Sstevel@tonic-gate 			_exit(errno);
2900Sstevel@tonic-gate 			/* NOTREACHED */
2910Sstevel@tonic-gate 		}
2920Sstevel@tonic-gate 	}
293238Sseizo 	return (0);
2940Sstevel@tonic-gate }
295