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
prb_child_create(const char * cmdname,char * const * cmdargs,const char * loption,const char * libtnfprobe_path,char * const * envp,prb_proc_ctl_t ** ret_val)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
prb_dbgaddr(prb_proc_ctl_t * proc_p,uintptr_t dbgaddr)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
sync_child(int childpid,volatile shmem_msg_t * smp,prb_proc_ctl_t ** proc_pp)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