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