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 (c) 1994, by Sun Microsytems, Inc. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * interfaces to exec a command and run it till all loadobjects have 30 * been loaded (rtld sync point). 31 */ 32 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <errno.h> 37 #include <limits.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 41 #include "prb_proc_int.h" 42 #include "dbg.h" 43 44 /* 45 * Defines 46 */ 47 48 #define PRELOAD "LD_PRELOAD" 49 #define LIBPROBE "libtnfprobe.so.1" 50 51 /* 52 * Local declarations 53 */ 54 55 static prb_status_t sync_child(int pid, volatile shmem_msg_t *smp, 56 prb_proc_ctl_t **proc_pp); 57 58 /* 59 * prb_child_create() - this routine instantiates and rendevous with the 60 * target child process. This routine returns an opaque handle for the 61 * childs /proc entry. 62 */ 63 prb_status_t 64 prb_child_create(const char *cmdname, char * const *cmdargs, 65 const char *loption, const char *libtnfprobe_path, 66 char * const *envp, prb_proc_ctl_t **ret_val) 67 { 68 prb_status_t prbstat; 69 pid_t childpid; 70 char executable_name[PATH_MAX + 2]; 71 extern char **environ; 72 char * const * env_to_use; 73 size_t loptlen, probepathlen; 74 volatile shmem_msg_t *smp; 75 76 /* initialize shmem communication buffer to cause child to wait */ 77 prbstat = prb_shmem_init(&smp); 78 if (prbstat) 79 return (prbstat); 80 81 /* fork to create the child process */ 82 childpid = fork(); 83 if (childpid == (pid_t) - 1) { 84 DBG(perror("prb_child_create: fork failed")); 85 return (prb_status_map(errno)); 86 } 87 if (childpid == 0) { 88 char *oldenv; 89 char *newenv; 90 91 /* ---- CHILD PROCESS ---- */ 92 93 DBG_TNF_PROBE_1(prb_child_create_1, "libtnfctl", 94 "sunw%verbosity 1; sunw%debug 'child process created'", 95 tnf_long, pid, getpid()); 96 97 if (envp) { 98 env_to_use = envp; 99 goto ContChild; 100 } 101 102 /* append libtnfprobe.so to the LD_PRELOAD environment */ 103 loptlen = (loption) ? strlen(loption) : 0; 104 /* probepathlen has a "/" added in ("+ 1") */ 105 probepathlen = (libtnfprobe_path) ? 106 (strlen(libtnfprobe_path) + 1) : 0; 107 oldenv = getenv(PRELOAD); 108 if (oldenv) { 109 newenv = (char *) malloc(strlen(PRELOAD) + 110 1 + /* "=" */ 111 strlen(oldenv) + 112 1 + /* " " */ 113 probepathlen + 114 strlen(LIBPROBE) + 115 1 + /* " " */ 116 loptlen + 117 1); /* NULL */ 118 119 if (!newenv) 120 goto ContChild; 121 (void) strcpy(newenv, PRELOAD); 122 (void) strcat(newenv, "="); 123 (void) strcat(newenv, oldenv); 124 (void) strcat(newenv, " "); 125 if (probepathlen) { 126 (void) strcat(newenv, libtnfprobe_path); 127 (void) strcat(newenv, "/"); 128 } 129 (void) strcat(newenv, LIBPROBE); 130 if (loptlen) { 131 (void) strcat(newenv, " "); 132 (void) strcat(newenv, loption); 133 } 134 } else { 135 newenv = (char *) malloc(strlen(PRELOAD) + 136 1 + /* "=" */ 137 probepathlen + 138 strlen(LIBPROBE) + 139 1 + /* " " */ 140 loptlen + 141 1); /* NULL */ 142 if (!newenv) 143 goto ContChild; 144 (void) strcpy(newenv, PRELOAD); 145 (void) strcat(newenv, "="); 146 if (probepathlen) { 147 (void) strcat(newenv, libtnfprobe_path); 148 (void) strcat(newenv, "/"); 149 } 150 (void) strcat(newenv, LIBPROBE); 151 if (loptlen) { 152 (void) strcat(newenv, " "); 153 (void) strcat(newenv, loption); 154 } 155 } 156 (void) putenv((char *) newenv); 157 env_to_use = environ; 158 /* 159 * We don't check the return value of putenv because the 160 * desired libraries might already be in the target, even 161 * if our effort to change the environment fails. We 162 * should continue either way ... 163 */ 164 ContChild: 165 /* wait until the parent releases us */ 166 (void) prb_shmem_wait(smp); 167 168 DBG_TNF_PROBE_1(prb_child_create_2, "libtnfctl", 169 "sunw%verbosity 2; " 170 "sunw%debug 'child process about to exec'", 171 tnf_string, cmdname, cmdname); 172 173 /* 174 * make the child it's own process group. 175 * This is so that signals delivered to parent are not 176 * also delivered to child. 177 */ 178 (void) setpgrp(); 179 prbstat = find_executable(cmdname, executable_name); 180 if (prbstat) { 181 DBG((void) fprintf(stderr, "prb_child_create: %s\n", 182 prb_status_str(prbstat))); 183 /* parent waits for exit */ 184 _exit(1); 185 } 186 if (execve(executable_name, cmdargs, env_to_use) == -1) { 187 DBG(perror("prb_child_create: exec failed")); 188 _exit(1); 189 } 190 191 /* Never reached */ 192 _exit(1); 193 } 194 /* ---- PARENT PROCESS ---- */ 195 /* child is waiting for us */ 196 197 prbstat = sync_child(childpid, smp, ret_val); 198 if (prbstat) { 199 return (prbstat); 200 } 201 202 return (PRB_STATUS_OK); 203 204 } 205 206 /* 207 * interface that registers the address of the debug structure 208 * in the target process. This is where the linker maintains all 209 * the information about the loadobjects 210 */ 211 void 212 prb_dbgaddr(prb_proc_ctl_t *proc_p, uintptr_t dbgaddr) 213 { 214 proc_p->dbgaddr = dbgaddr; 215 } 216 217 /* 218 * continue the child until the run time linker has loaded in all 219 * the loadobjects (rtld sync point) 220 */ 221 static prb_status_t 222 sync_child(int childpid, volatile shmem_msg_t *smp, prb_proc_ctl_t **proc_pp) 223 { 224 prb_proc_ctl_t *proc_p, *oldproc_p; 225 prb_status_t prbstat = PRB_STATUS_OK; 226 prb_status_t tempstat; 227 prb_proc_state_t pstate; 228 229 prbstat = prb_proc_open(childpid, proc_pp); 230 if (prbstat) 231 return (prbstat); 232 233 proc_p = *proc_pp; 234 235 prbstat = prb_proc_stop(proc_p); 236 if (prbstat) 237 goto ret_failure; 238 239 /* 240 * default is to kill-on-last-close. In case we cannot sync with 241 * target, we don't want the target to continue. 242 */ 243 prbstat = prb_proc_setrlc(proc_p, B_FALSE); 244 if (prbstat) 245 goto ret_failure; 246 247 prbstat = prb_proc_setklc(proc_p, B_TRUE); 248 if (prbstat) 249 goto ret_failure; 250 251 /* REMIND: do we have to wait on SYS_exec also ? */ 252 prbstat = prb_proc_exit(proc_p, SYS_execve, PRB_SYS_ADD); 253 if (prbstat) 254 goto ret_failure; 255 256 prbstat = prb_proc_entry(proc_p, SYS_exit, PRB_SYS_ADD); 257 if (prbstat) 258 goto ret_failure; 259 260 prbstat = prb_shmem_clear(smp); 261 if (prbstat) 262 goto ret_failure; 263 264 prbstat = prb_proc_cont(proc_p); 265 if (prbstat) 266 goto ret_failure; 267 268 prbstat = prb_proc_wait(proc_p, B_FALSE, NULL); 269 switch (prbstat) { 270 case PRB_STATUS_OK: 271 break; 272 case EAGAIN: 273 /* 274 * If we had exec'ed a setuid/setgid program PIOCWSTOP 275 * will return EAGAIN. Reopen the 'fd' and try again. 276 * Read the last section of /proc man page - we reopen first 277 * and then close the old fd. 278 */ 279 oldproc_p = proc_p; 280 tempstat = prb_proc_reopen(childpid, proc_pp); 281 proc_p = *proc_pp; 282 if (tempstat) { 283 /* here EACCES means exec'ed a setuid/setgid program */ 284 (void) prb_proc_close(oldproc_p); 285 return (tempstat); 286 } 287 288 (void) prb_proc_close(oldproc_p); 289 break; 290 default: 291 goto ret_failure; 292 } 293 294 prbstat = prb_shmem_free(smp); 295 if (prbstat) 296 goto ret_failure; 297 298 prbstat = prb_proc_state(proc_p, &pstate); 299 if (prbstat) 300 goto ret_failure; 301 302 if (pstate.ps_issysexit && (pstate.ps_syscallnum == SYS_execve)) { 303 /* expected condition */ 304 prbstat = PRB_STATUS_OK; 305 } else { 306 prbstat = prb_status_map(ENOENT); 307 goto ret_failure; 308 } 309 310 /* clear old interest mask */ 311 prbstat = prb_proc_exit(proc_p, 0, PRB_SYS_NONE); 312 if (prbstat) 313 goto ret_failure; 314 315 prbstat = prb_proc_entry(proc_p, 0, PRB_SYS_NONE); 316 if (prbstat) 317 goto ret_failure; 318 319 /* Successful return */ 320 return (PRB_STATUS_OK); 321 322 ret_failure: 323 (void) prb_proc_close(proc_p); 324 return (prbstat); 325 } 326