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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <stdio.h> 30 #include <errno.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <wait.h> 34 #include <limits.h> 35 #include <gelf.h> 36 #include "machdep.h" 37 #include "sgs.h" 38 #include "conv.h" 39 #include "_crle.h" 40 #include "msg.h" 41 42 /* 43 * Establish an association between a filter and filtee. Both the filter and 44 * filtee already exist in the internal hash table, since auditing registers 45 * objects (la_objopen()) before it registers filters (la_objfilter()). 46 */ 47 static int 48 filter(Crle_desc *crle, const char *filter, const char *str, const char *filtee) 49 { 50 Hash_ent * fltrent, * flteent; 51 Flt_desc * flt; 52 Listnode * lnp; 53 54 /* 55 * Locate the filter. Mark the underlying object as the filter to 56 * reflect that no matter how it is referenced, it's a filter. 57 */ 58 if ((fltrent = get_hash(crle->c_strtbl, (Addr)filter, 0, 59 HASH_FND_ENT)) == 0) 60 return (1); 61 if ((fltrent = get_hash(crle->c_strtbl, (Addr)fltrent->e_obj->o_path, 0, 62 HASH_FND_ENT)) == 0) 63 return (1); 64 fltrent->e_obj->o_flags |= RTC_OBJ_FILTER; 65 66 /* 67 * Locate the filtee. Mark the referencing object as the filtee, as 68 * this is the object referenced by the filter. 69 */ 70 if ((flteent = get_hash(crle->c_strtbl, (Addr)filtee, 0, 71 HASH_FND_ENT)) == 0) 72 return (1); 73 flteent->e_flags |= RTC_OBJ_FILTEE; 74 75 /* 76 * Traverse the filter list using the filters real name. If ld.so.1 77 * inspects the resulting configuration file for filters, it's the 78 * objects real name that will be used (PATHNAME()). 79 */ 80 for (LIST_TRAVERSE(&(crle->c_flt), lnp, flt)) { 81 /* 82 * Determine whether this filter and filtee string pair already 83 * exist. 84 */ 85 if ((strcmp(flt->f_fent->e_obj->o_path, 86 fltrent->e_obj->o_path) != 0) && 87 (strcmp(flt->f_str, str) != 0)) 88 continue; 89 90 /* 91 * Add this filtee additional association. 92 */ 93 if (list_append(&(flt->f_filtee), flteent) == 0) 94 return (1); 95 96 crle->c_fltenum++; 97 return (0); 98 } 99 100 /* 101 * This is a new filter descriptor. Add this new filtee association. 102 */ 103 if (((flt = malloc(sizeof (Flt_desc))) == 0) || 104 ((flt->f_strsz = strlen(str) + 1) == 0) || 105 ((flt->f_str = malloc(flt->f_strsz)) == 0)) { 106 int err = errno; 107 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), 108 crle->c_name, strerror(err)); 109 return (1); 110 } 111 if ((list_append(&(crle->c_flt), flt) == 0) || 112 (list_append(&(flt->f_filtee), flteent) == 0)) 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 = 0; 143 } else { 144 exename = conv_lddstub(crle->c_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