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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 #include <sys/types.h> 28 #include <stdio.h> 29 #include <errno.h> 30 #include <unistd.h> 31 #include <string.h> 32 #include <wait.h> 33 #include <limits.h> 34 #include <gelf.h> 35 #include "machdep.h" 36 #include "sgs.h" 37 #include "conv.h" 38 #include "_crle.h" 39 #include "msg.h" 40 41 /* 42 * Establish an association between a filter and filtee. Both the filter and 43 * filtee already exist in the internal hash table, since auditing registers 44 * objects (la_objopen()) before it registers filters (la_objfilter()). 45 */ 46 static int 47 filter(Crle_desc *crle, const char *filter, const char *str, const char *filtee) 48 { 49 Hash_ent * fltrent, * flteent; 50 Flt_desc * flt; 51 Listnode * lnp; 52 53 /* 54 * Locate the filter. Mark the underlying object as the filter to 55 * reflect that no matter how it is referenced, it's a filter. 56 */ 57 if ((fltrent = get_hash(crle->c_strtbl, (Addr)filter, 0, 58 HASH_FND_ENT)) == 0) 59 return (1); 60 if ((fltrent = get_hash(crle->c_strtbl, (Addr)fltrent->e_obj->o_path, 0, 61 HASH_FND_ENT)) == 0) 62 return (1); 63 fltrent->e_obj->o_flags |= RTC_OBJ_FILTER; 64 65 /* 66 * Locate the filtee. Mark the referencing object as the filtee, as 67 * this is the object referenced by the filter. 68 */ 69 if ((flteent = get_hash(crle->c_strtbl, (Addr)filtee, 0, 70 HASH_FND_ENT)) == 0) 71 return (1); 72 flteent->e_flags |= RTC_OBJ_FILTEE; 73 74 /* 75 * Traverse the filter list using the filters real name. If ld.so.1 76 * inspects the resulting configuration file for filters, it's the 77 * objects real name that will be used (PATHNAME()). 78 */ 79 for (LIST_TRAVERSE(&(crle->c_flt), lnp, flt)) { 80 /* 81 * Determine whether this filter and filtee string pair already 82 * exist. 83 */ 84 if ((strcmp(flt->f_fent->e_obj->o_path, 85 fltrent->e_obj->o_path) != 0) && 86 (strcmp(flt->f_str, str) != 0)) 87 continue; 88 89 /* 90 * Add this filtee additional association. 91 */ 92 if (list_append(&(flt->f_filtee), flteent) == 0) 93 return (1); 94 95 crle->c_fltenum++; 96 return (0); 97 } 98 99 /* 100 * This is a new filter descriptor. Add this new filtee association. 101 */ 102 if (((flt = malloc(sizeof (Flt_desc))) == 0) || 103 ((flt->f_strsz = strlen(str) + 1) == 0) || 104 ((flt->f_str = malloc(flt->f_strsz)) == 0)) { 105 int err = errno; 106 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), 107 crle->c_name, strerror(err)); 108 return (1); 109 } 110 if ((list_append(&(crle->c_flt), flt) == 0) || 111 (list_append(&(flt->f_filtee), flteent) == 0)) 112 return (1); 113 114 flt->f_fent = fltrent; 115 (void) memcpy((void *)flt->f_str, (void *)str, flt->f_strsz); 116 crle->c_strsize += flt->f_strsz; 117 crle->c_fltrnum += 1; 118 crle->c_fltenum += 2; /* Account for null filtee desc. */ 119 120 return (0); 121 } 122 123 /* 124 * Establish the dependencies of an ELF object and add them to the internal 125 * configuration information. This information is gathered by using libcrle.so.1 126 * as an audit library - this is akin to using ldd(1) only simpler. 127 */ 128 int 129 depend(Crle_desc *crle, const char *name, Half flags, GElf_Ehdr *ehdr) 130 { 131 const char *exename; 132 const char *preload; 133 int fildes[2], pid; 134 135 /* 136 * If we're dealing with a dynamic executable we'll execute it, 137 * otherwise we'll preload the shared object with one of the lddstub's. 138 */ 139 if (ehdr->e_type == ET_EXEC) { 140 exename = name; 141 preload = 0; 142 } else { 143 exename = conv_lddstub(M_CLASS); 144 preload = name; 145 } 146 147 /* 148 * Set up a pipe through which the audit library will write the 149 * dependencies. 150 */ 151 if (pipe(fildes) == -1) { 152 int err = errno; 153 (void) fprintf(stderr, MSG_INTL(MSG_SYS_PIPE), 154 crle->c_name, strerror(err)); 155 return (1); 156 } 157 158 /* 159 * Fork ourselves to run our executable and collect its dependencies. 160 */ 161 if ((pid = fork()) == -1) { 162 int err = errno; 163 (void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK), 164 crle->c_name, strerror(err)); 165 return (1); 166 } 167 168 if (pid) { 169 /* 170 * Parent. Read each dependency from the audit library. The read 171 * side of the pipe is attached to stdio to make obtaining the 172 * individual dependencies easier. 173 */ 174 int error = 0, status; 175 FILE *fd; 176 char buffer[PATH_MAX]; 177 178 (void) close(fildes[1]); 179 if ((fd = fdopen(fildes[0], MSG_ORIG(MSG_STR_READ))) != NULL) { 180 char *str; 181 182 while (fgets(buffer, PATH_MAX, fd) != NULL) { 183 /* 184 * Make sure we recognize the message, remove 185 * the newline (which allowed fgets() use) and 186 * register the name; 187 */ 188 if (strncmp(MSG_ORIG(MSG_AUD_PRF), buffer, 189 MSG_AUD_PRF_SIZE)) 190 continue; 191 192 str = strrchr(buffer, '\n'); 193 *str = '\0'; 194 str = buffer + MSG_AUD_PRF_SIZE; 195 196 if (strncmp(MSG_ORIG(MSG_AUD_DEPEND), 197 str, MSG_AUD_DEPEND_SIZE) == 0) { 198 /* 199 * Process any dependencies. 200 */ 201 str += MSG_AUD_DEPEND_SIZE; 202 203 if ((error = inspect(crle, str, 204 (flags & ~RTC_OBJ_GROUP))) != 0) 205 break; 206 207 } else if (strncmp(MSG_ORIG(MSG_AUD_FILTER), 208 str, MSG_AUD_FILTER_SIZE) == 0) { 209 char *_flt, *_str; 210 211 /* 212 * Process any filters. 213 */ 214 _flt = str += MSG_AUD_FILTER_SIZE; 215 _str = strchr(str, ':'); 216 *_str++ = '\0'; str = _str++; 217 str = strrchr(str, ')'); 218 *str++ = '\0'; str++; 219 if ((error = filter(crle, _flt, _str, 220 str)) != 0) 221 break; 222 } 223 } 224 } else 225 error = errno; 226 227 while (wait(&status) != pid) 228 ; 229 if (status) { 230 if (WIFSIGNALED(status)) { 231 (void) fprintf(stderr, 232 MSG_INTL(MSG_SYS_EXEC), crle->c_name, 233 exename, (WSIGMASK & status), 234 ((status & WCOREFLG) ? 235 MSG_INTL(MSG_SYS_CORE) : 236 MSG_ORIG(MSG_STR_EMPTY))); 237 } 238 error = status; 239 } 240 (void) fclose(fd); 241 242 return (error); 243 } else { 244 char efds[MSG_ENV_AUD_FD_SIZE + 10]; 245 char epld[PATH_MAX]; 246 char eldf[PATH_MAX]; 247 248 (void) close(fildes[0]); 249 250 /* 251 * Child. Set up environment variables to enable and identify 252 * auditing. Initialize CRLE_FD and LD_FLAGS strings. 253 */ 254 (void) snprintf(efds, (MSG_ENV_AUD_FD_SIZE + 10), 255 MSG_ORIG(MSG_ENV_AUD_FD), fildes[1]); 256 (void) snprintf(eldf, PATH_MAX, MSG_ORIG(MSG_ENV_LD_FLAGS)); 257 258 /* 259 * If asked to dump a group of dependencies make sure any 260 * lazily-loaded objects get processed - (append loadavail to 261 * LD_FLAGS=confgen). 262 */ 263 if (flags & RTC_OBJ_GROUP) 264 (void) strcat(eldf, MSG_ORIG(MSG_LDFLG_LOADAVAIL)); 265 266 /* 267 * Put LD_PRELOAD= in the environment if necessary. 268 */ 269 if (preload) { 270 (void) snprintf(epld, PATH_MAX, 271 MSG_ORIG(MSG_ENV_LD_PRELOAD), preload); 272 } 273 274 /* 275 * Put strings in the environment for exec(). 276 * NOTE, use of automatic variables for construction of the 277 * environment variables is legitimate here, as they are local 278 * to the child process and are established solely for exec(). 279 */ 280 if ((putenv(efds) != 0) || (putenv(crle->c_audit) != 0) || 281 (putenv(eldf) != 0) || (preload && (putenv(epld) != 0))) { 282 int err = errno; 283 (void) fprintf(stderr, MSG_INTL(MSG_SYS_PUTENV), 284 crle->c_name, strerror(err)); 285 return (1); 286 } 287 288 if (execlp(exename, exename, 0) == -1) { 289 _exit(errno); 290 /* NOTREACHED */ 291 } 292 } 293 return (0); 294 } 295