xref: /onnv-gate/usr/src/lib/libkvm/common/kvm_getcmd.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <kvm.h>
30*0Sstevel@tonic-gate #include <stdio.h>
31*0Sstevel@tonic-gate #include <stdlib.h>
32*0Sstevel@tonic-gate #include <unistd.h>
33*0Sstevel@tonic-gate #include <fcntl.h>
34*0Sstevel@tonic-gate #include <kvm.h>
35*0Sstevel@tonic-gate #include <strings.h>
36*0Sstevel@tonic-gate #include <sys/types32.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #define	_SYSCALL32
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate /*
41*0Sstevel@tonic-gate  * VERSION FOR MACHINES WITH STACKS GROWING DOWNWARD IN MEMORY
42*0Sstevel@tonic-gate  *
43*0Sstevel@tonic-gate  * On program entry, the top of the stack frame looks like this:
44*0Sstevel@tonic-gate  *
45*0Sstevel@tonic-gate  * hi:	|-----------------------|
46*0Sstevel@tonic-gate  *	|	unspecified	|
47*0Sstevel@tonic-gate  *	|-----------------------|+
48*0Sstevel@tonic-gate  *	|	   :		| \
49*0Sstevel@tonic-gate  *	|  arg and env strings	|  > no more than NCARGS bytes
50*0Sstevel@tonic-gate  *	|	   :		| /
51*0Sstevel@tonic-gate  *	|-----------------------|+
52*0Sstevel@tonic-gate  *	|	unspecified	|
53*0Sstevel@tonic-gate  *	|-----------------------|
54*0Sstevel@tonic-gate  *	| null auxiliary vector	|
55*0Sstevel@tonic-gate  *	|-----------------------|
56*0Sstevel@tonic-gate  *	|   auxiliary vector	|
57*0Sstevel@tonic-gate  *	|   (2-word entries)	|
58*0Sstevel@tonic-gate  *	|	   :		|
59*0Sstevel@tonic-gate  *	|-----------------------|
60*0Sstevel@tonic-gate  *	|	(char *)0	|
61*0Sstevel@tonic-gate  *	|-----------------------|
62*0Sstevel@tonic-gate  *	|  ptrs to env strings	|
63*0Sstevel@tonic-gate  *	|	   :		|
64*0Sstevel@tonic-gate  *	|-----------------------|
65*0Sstevel@tonic-gate  *	|	(char *)0	|
66*0Sstevel@tonic-gate  *	|-----------------------|
67*0Sstevel@tonic-gate  *	|  ptrs to arg strings	|
68*0Sstevel@tonic-gate  *	|   (argc = # of ptrs)	|
69*0Sstevel@tonic-gate  *	|	   :		|
70*0Sstevel@tonic-gate  *	|-----------------------|
71*0Sstevel@tonic-gate  *	|	  argc		|
72*0Sstevel@tonic-gate  * low:	|-----------------------|
73*0Sstevel@tonic-gate  */
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate #define	RoundUp(v, t)	(((v) + sizeof (t) - 1) & ~(sizeof (t) - 1))
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate static int
kvm_getcmd32(kvm_t * kd,struct proc * p,struct user * u,char *** arg,char *** env)78*0Sstevel@tonic-gate kvm_getcmd32(kvm_t *kd,
79*0Sstevel@tonic-gate     struct proc *p, struct user *u, char ***arg, char ***env)
80*0Sstevel@tonic-gate {
81*0Sstevel@tonic-gate #if defined(_LP64) || defined(lint)
82*0Sstevel@tonic-gate 	size_t size32;
83*0Sstevel@tonic-gate 	void *stack32;
84*0Sstevel@tonic-gate 	int i, argc, envc;
85*0Sstevel@tonic-gate 	int auxc = 0;
86*0Sstevel@tonic-gate 	size_t asize, esize;
87*0Sstevel@tonic-gate 	char **argv = NULL;
88*0Sstevel@tonic-gate 	char **envp = NULL;
89*0Sstevel@tonic-gate 	size_t strpoolsz;
90*0Sstevel@tonic-gate 	int aptrcount;
91*0Sstevel@tonic-gate 	int eptrcount;
92*0Sstevel@tonic-gate 	caddr_t stackp;
93*0Sstevel@tonic-gate 	ptrdiff_t reloc;
94*0Sstevel@tonic-gate 	char *str;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	/*
97*0Sstevel@tonic-gate 	 * Bring the entire stack into memory first, size it
98*0Sstevel@tonic-gate 	 * as an LP64 user stack, then allocate and copy into
99*0Sstevel@tonic-gate 	 * the buffer(s) to be returned to the caller.
100*0Sstevel@tonic-gate 	 */
101*0Sstevel@tonic-gate 	size32 = (size_t)p->p_usrstack - (size_t)u->u_argv;
102*0Sstevel@tonic-gate 	if ((stack32 = malloc(size32)) == NULL)
103*0Sstevel@tonic-gate 		return (-1);
104*0Sstevel@tonic-gate 	if (kvm_uread(kd, (uintptr_t)u->u_argv, stack32, size32) != size32) {
105*0Sstevel@tonic-gate 		free(stack32);
106*0Sstevel@tonic-gate 		return (-1);
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	/*
110*0Sstevel@tonic-gate 	 * Find the interesting sizes of a 32-bit stack.
111*0Sstevel@tonic-gate 	 */
112*0Sstevel@tonic-gate 	argc = u->u_argc;
113*0Sstevel@tonic-gate 	stackp = (caddr_t)stack32 + ((1 + argc) * sizeof (caddr32_t));
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	for (envc = 0; *(caddr32_t *)stackp; envc++) {
116*0Sstevel@tonic-gate 		stackp += sizeof (caddr32_t);
117*0Sstevel@tonic-gate 		if ((stackp - (caddr_t)stack32) >= size32) {
118*0Sstevel@tonic-gate 			free(stack32);
119*0Sstevel@tonic-gate 			return (-1);
120*0Sstevel@tonic-gate 		}
121*0Sstevel@tonic-gate 	}
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	if (u->u_auxv[0].a_type != AT_NULL) {
124*0Sstevel@tonic-gate 		stackp += sizeof (caddr32_t);
125*0Sstevel@tonic-gate 		for (auxc = 0; *(int32_t *)stackp; auxc++) {
126*0Sstevel@tonic-gate 			stackp += 2 * sizeof (caddr32_t);
127*0Sstevel@tonic-gate 			if ((stackp - (caddr_t)stack32) >= size32) {
128*0Sstevel@tonic-gate 				free(stack32);
129*0Sstevel@tonic-gate 				return (-1);
130*0Sstevel@tonic-gate 			}
131*0Sstevel@tonic-gate 		}
132*0Sstevel@tonic-gate 		auxc++;		/* terminating AT_NULL record */
133*0Sstevel@tonic-gate 	}
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	/*
136*0Sstevel@tonic-gate 	 * Compute the sizes of the stuff we're going to allocate or copy.
137*0Sstevel@tonic-gate 	 */
138*0Sstevel@tonic-gate 	eptrcount = (envc + 1) + 2 * auxc;
139*0Sstevel@tonic-gate 	aptrcount = (argc + 1) + eptrcount;
140*0Sstevel@tonic-gate 	strpoolsz = size32 - aptrcount * sizeof (caddr32_t);
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	asize = aptrcount * sizeof (uintptr_t) + RoundUp(strpoolsz, uintptr_t);
143*0Sstevel@tonic-gate 	if (arg && (argv = calloc(1, asize + sizeof (uintptr_t))) == NULL) {
144*0Sstevel@tonic-gate 		free(stack32);
145*0Sstevel@tonic-gate 		return (-1);
146*0Sstevel@tonic-gate 	}
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	esize = eptrcount * sizeof (uintptr_t) + RoundUp(strpoolsz, uintptr_t);
149*0Sstevel@tonic-gate 	if (env && (envp = calloc(1, esize + sizeof (uintptr_t))) == NULL) {
150*0Sstevel@tonic-gate 		if (argv)
151*0Sstevel@tonic-gate 			free(argv);
152*0Sstevel@tonic-gate 		free(stack32);
153*0Sstevel@tonic-gate 		return (-1);
154*0Sstevel@tonic-gate 	}
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	/*
157*0Sstevel@tonic-gate 	 * Walk up the 32-bit stack, filling in the 64-bit argv and envp
158*0Sstevel@tonic-gate 	 * as we go.
159*0Sstevel@tonic-gate 	 */
160*0Sstevel@tonic-gate 	stackp = (caddr_t)stack32;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	/*
163*0Sstevel@tonic-gate 	 * argument vector
164*0Sstevel@tonic-gate 	 */
165*0Sstevel@tonic-gate 	if (argv) {
166*0Sstevel@tonic-gate 		for (i = 0; i < argc; i++) {
167*0Sstevel@tonic-gate 			argv[i] = (char *)(uintptr_t)(*(caddr32_t *)stackp);
168*0Sstevel@tonic-gate 			stackp += sizeof (caddr32_t);
169*0Sstevel@tonic-gate 		}
170*0Sstevel@tonic-gate 		argv[argc] = 0;
171*0Sstevel@tonic-gate 		stackp += sizeof (caddr32_t);
172*0Sstevel@tonic-gate 	} else
173*0Sstevel@tonic-gate 		stackp += (1 + argc) * sizeof (caddr32_t);
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	/*
176*0Sstevel@tonic-gate 	 * environment
177*0Sstevel@tonic-gate 	 */
178*0Sstevel@tonic-gate 	if (envp) {
179*0Sstevel@tonic-gate 		for (i = 0; i < envc; i++) {
180*0Sstevel@tonic-gate 			envp[i] = (char *)(uintptr_t)(*(caddr32_t *)stackp);
181*0Sstevel@tonic-gate 			stackp += sizeof (caddr32_t);
182*0Sstevel@tonic-gate 		}
183*0Sstevel@tonic-gate 		envp[envc] = 0;
184*0Sstevel@tonic-gate 		stackp += sizeof (caddr32_t);
185*0Sstevel@tonic-gate 	} else
186*0Sstevel@tonic-gate 		stackp += (1 + envc) * sizeof (caddr32_t);
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	/*
189*0Sstevel@tonic-gate 	 * auxiliary vector (skip it..)
190*0Sstevel@tonic-gate 	 */
191*0Sstevel@tonic-gate 	stackp += auxc * (sizeof (int32_t) + sizeof (uint32_t));
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	/*
194*0Sstevel@tonic-gate 	 * Copy the string pool, untranslated
195*0Sstevel@tonic-gate 	 */
196*0Sstevel@tonic-gate 	if (argv)
197*0Sstevel@tonic-gate 		(void) memcpy(argv + aptrcount, (void *)stackp, strpoolsz);
198*0Sstevel@tonic-gate 	if (envp)
199*0Sstevel@tonic-gate 		(void) memcpy(envp + eptrcount, (void *)stackp, strpoolsz);
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	free(stack32);
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	/*
204*0Sstevel@tonic-gate 	 * Relocate the pointers to point at the newly allocated space.
205*0Sstevel@tonic-gate 	 * Use the same algorithms as kvm_getcmd to handle naughty
206*0Sstevel@tonic-gate 	 * changes to the argv and envp arrays.
207*0Sstevel@tonic-gate 	 */
208*0Sstevel@tonic-gate 	if (argv) {
209*0Sstevel@tonic-gate 		char *argv_null = (char *)argv + asize;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 		reloc = (char *)(argv + aptrcount) - (char *)
212*0Sstevel@tonic-gate 		    ((caddr_t)u->u_argv + aptrcount * sizeof (caddr32_t));
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 		for (i = 0; i < argc; i++)
215*0Sstevel@tonic-gate 			if (argv[i] != NULL) {
216*0Sstevel@tonic-gate 				str = (argv[i] += reloc);
217*0Sstevel@tonic-gate 				if (str < (char *)argv ||
218*0Sstevel@tonic-gate 				    str >= (char *)argv + asize)
219*0Sstevel@tonic-gate 					argv[i] = argv_null;
220*0Sstevel@tonic-gate 			}
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 		*arg = argv;
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	if (envp) {
226*0Sstevel@tonic-gate 		char *envp_null = (char *)envp + esize;
227*0Sstevel@tonic-gate 		char *last_str;
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 		reloc = (char *)(envp + eptrcount) - (char *)
230*0Sstevel@tonic-gate 		    ((caddr_t)u->u_envp + eptrcount * sizeof (caddr32_t));
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 		last_str = (char *)((size_t)u->u_argv +
233*0Sstevel@tonic-gate 		    (1 + argc) * sizeof (caddr32_t) + reloc);
234*0Sstevel@tonic-gate 		if (last_str < (char *)envp ||
235*0Sstevel@tonic-gate 		    last_str >= (char *)envp + esize)
236*0Sstevel@tonic-gate 			last_str = envp_null;
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 		for (i = 0; i < envc; i++) {
239*0Sstevel@tonic-gate 			str = (envp[i] += reloc);
240*0Sstevel@tonic-gate 			if (str < (char *)envp ||
241*0Sstevel@tonic-gate 			    str >= (char *)envp + esize) {
242*0Sstevel@tonic-gate 				if (last_str != envp_null)
243*0Sstevel@tonic-gate 					envp[i] = (char *)((size_t)last_str +
244*0Sstevel@tonic-gate 					    strlen(last_str) + 1);
245*0Sstevel@tonic-gate 				else
246*0Sstevel@tonic-gate 					envp[i] = envp_null;
247*0Sstevel@tonic-gate 			}
248*0Sstevel@tonic-gate 			last_str = envp[i];
249*0Sstevel@tonic-gate 		}
250*0Sstevel@tonic-gate 		*env = envp;
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate #endif	/* _LP64 || lint */
253*0Sstevel@tonic-gate 	return (0);
254*0Sstevel@tonic-gate }
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate /*
257*0Sstevel@tonic-gate  * reconstruct an argv-like argument list from the target process
258*0Sstevel@tonic-gate  */
259*0Sstevel@tonic-gate int
kvm_getcmd(kvm_t * kd,struct proc * proc,struct user * u,char *** arg,char *** env)260*0Sstevel@tonic-gate kvm_getcmd(kvm_t *kd,
261*0Sstevel@tonic-gate     struct proc *proc, struct user *u, char ***arg, char ***env)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate 	size_t asize;
264*0Sstevel@tonic-gate 	size_t esize;
265*0Sstevel@tonic-gate 	size_t offset;
266*0Sstevel@tonic-gate 	int i;
267*0Sstevel@tonic-gate 	int argc;
268*0Sstevel@tonic-gate 	char **argv = NULL;
269*0Sstevel@tonic-gate 	char **envp = NULL;
270*0Sstevel@tonic-gate 	char *str;
271*0Sstevel@tonic-gate 	char *last_str;
272*0Sstevel@tonic-gate 	char *argv_null;	/* Known null in the returned argv */
273*0Sstevel@tonic-gate 	char *envp_null;	/* Known null in the returned envp */
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	if (proc->p_flag & SSYS)	/* system process */
276*0Sstevel@tonic-gate 		return (-1);
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	/*
279*0Sstevel@tonic-gate 	 * Protect against proc structs found by kvm_nextproc()
280*0Sstevel@tonic-gate 	 * while the kernel was doing a fork(). Such a proc struct
281*0Sstevel@tonic-gate 	 * may have p_usrstack set but a still zeroed uarea.
282*0Sstevel@tonic-gate 	 * We wouldn't want to unecessarily allocate 4GB memory ...
283*0Sstevel@tonic-gate 	 */
284*0Sstevel@tonic-gate 	if (u->u_argv == NULL || u->u_envp == NULL)
285*0Sstevel@tonic-gate 		return (-1);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	/*
288*0Sstevel@tonic-gate 	 * If this is a 32-bit process running on a 64-bit system,
289*0Sstevel@tonic-gate 	 * then the stack is laid out using ILP32 pointers, not LP64.
290*0Sstevel@tonic-gate 	 * To minimize potential confusion, we blow it up to "LP64
291*0Sstevel@tonic-gate 	 * shaped" right here.
292*0Sstevel@tonic-gate 	 */
293*0Sstevel@tonic-gate 	if (proc->p_model != DATAMODEL_NATIVE &&
294*0Sstevel@tonic-gate 	    proc->p_model == DATAMODEL_ILP32)
295*0Sstevel@tonic-gate 		return (kvm_getcmd32(kd, proc, u, arg, env));
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	/*
298*0Sstevel@tonic-gate 	 * Space for the stack, from the argument vector.  An additional
299*0Sstevel@tonic-gate 	 * word is added to guarantee a NULL word terminates the buffer.
300*0Sstevel@tonic-gate 	 */
301*0Sstevel@tonic-gate 	if (arg) {
302*0Sstevel@tonic-gate 		asize = (size_t)proc->p_usrstack - (size_t)u->u_argv;
303*0Sstevel@tonic-gate 		if ((argv = malloc(asize + sizeof (uintptr_t))) == NULL)
304*0Sstevel@tonic-gate 			return (-1);
305*0Sstevel@tonic-gate 		argv_null = (char *)argv + asize;
306*0Sstevel@tonic-gate 		*(uintptr_t *)argv_null = 0;
307*0Sstevel@tonic-gate 	}
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	/*
310*0Sstevel@tonic-gate 	 * Space for the stack, from the environment vector.  An additional
311*0Sstevel@tonic-gate 	 * word is added to guarantee a NULL word terminates the buffer.
312*0Sstevel@tonic-gate 	 */
313*0Sstevel@tonic-gate 	if (env) {
314*0Sstevel@tonic-gate 		esize = (size_t)proc->p_usrstack - (size_t)u->u_envp;
315*0Sstevel@tonic-gate 		if ((envp = malloc(esize + sizeof (uintptr_t))) == NULL) {
316*0Sstevel@tonic-gate 			if (argv)
317*0Sstevel@tonic-gate 				free(argv);
318*0Sstevel@tonic-gate 			return (-1);
319*0Sstevel@tonic-gate 		}
320*0Sstevel@tonic-gate 		envp_null = (char *)envp + esize;
321*0Sstevel@tonic-gate 		*(uintptr_t *)envp_null = 0;
322*0Sstevel@tonic-gate 	}
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	argc = u->u_argc;
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	if (argv) {
327*0Sstevel@tonic-gate 		/* read the whole initial stack */
328*0Sstevel@tonic-gate 		if (kvm_uread(kd,
329*0Sstevel@tonic-gate 		    (uintptr_t)u->u_argv, argv, asize) != asize) {
330*0Sstevel@tonic-gate 			free(argv);
331*0Sstevel@tonic-gate 			if (envp)
332*0Sstevel@tonic-gate 				free(envp);
333*0Sstevel@tonic-gate 			return (-1);
334*0Sstevel@tonic-gate 		}
335*0Sstevel@tonic-gate 		argv[argc] = 0;
336*0Sstevel@tonic-gate 		if (envp) {
337*0Sstevel@tonic-gate 			/*
338*0Sstevel@tonic-gate 			 * Copy it to the malloc()d space for the envp array
339*0Sstevel@tonic-gate 			 */
340*0Sstevel@tonic-gate 			(void) memcpy(envp, &argv[argc + 1], esize);
341*0Sstevel@tonic-gate 		}
342*0Sstevel@tonic-gate 	} else if (envp) {
343*0Sstevel@tonic-gate 		/* read most of the initial stack (excluding argv) */
344*0Sstevel@tonic-gate 		if (kvm_uread(kd,
345*0Sstevel@tonic-gate 		    (uintptr_t)u->u_envp, envp, esize) != esize) {
346*0Sstevel@tonic-gate 			free(envp);
347*0Sstevel@tonic-gate 			return (-1);
348*0Sstevel@tonic-gate 		}
349*0Sstevel@tonic-gate 	}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	/*
352*0Sstevel@tonic-gate 	 * Relocate and sanity check the argv array.  Entries which have
353*0Sstevel@tonic-gate 	 * been explicity nulled are left that way.  Entries which have
354*0Sstevel@tonic-gate 	 * been replaced are pointed to a null string.  Well behaved apps
355*0Sstevel@tonic-gate 	 * don't do any of this.
356*0Sstevel@tonic-gate 	 */
357*0Sstevel@tonic-gate 	if (argv) {
358*0Sstevel@tonic-gate 		/* relocate the argv[] addresses */
359*0Sstevel@tonic-gate 		offset = (char *)argv - (char *)u->u_argv;
360*0Sstevel@tonic-gate 		for (i = 0; i < argc; i++) {
361*0Sstevel@tonic-gate 			if (argv[i] != NULL) {
362*0Sstevel@tonic-gate 				str = (argv[i] += offset);
363*0Sstevel@tonic-gate 				if (str < (char *)argv ||
364*0Sstevel@tonic-gate 				    str >= (char *)argv + asize)
365*0Sstevel@tonic-gate 					argv[i] = argv_null;
366*0Sstevel@tonic-gate 			}
367*0Sstevel@tonic-gate 		}
368*0Sstevel@tonic-gate 		argv[i] = NULL;
369*0Sstevel@tonic-gate 		*arg = argv;
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	/*
373*0Sstevel@tonic-gate 	 * Relocate and sanity check the envp array.  A null entry indicates
374*0Sstevel@tonic-gate 	 * the end of the environment.  Entries which point outside of the
375*0Sstevel@tonic-gate 	 * initial stack are replaced with what must have been the initial
376*0Sstevel@tonic-gate 	 * value based on the known ordering of the string table by the
377*0Sstevel@tonic-gate 	 * kernel.  If stack corruption prevents the calculation of the
378*0Sstevel@tonic-gate 	 * location of an initial string value, a pointer to a null string
379*0Sstevel@tonic-gate 	 * is returned.  To return a null pointer would prematurely terminate
380*0Sstevel@tonic-gate 	 * the list.  Well behaved apps do set pointers outside of the
381*0Sstevel@tonic-gate 	 * initial stack via the putenv(3C) library routine.
382*0Sstevel@tonic-gate 	 */
383*0Sstevel@tonic-gate 	if (envp) {
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 		/*
386*0Sstevel@tonic-gate 		 * Determine the start of the environment strings as one
387*0Sstevel@tonic-gate 		 * past the last argument string.
388*0Sstevel@tonic-gate 		 */
389*0Sstevel@tonic-gate 		offset = (char *)envp - (char *)u->u_envp;
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 		if (kvm_uread(kd,
392*0Sstevel@tonic-gate 		    (uintptr_t)u->u_argv + (argc - 1) * sizeof (char **),
393*0Sstevel@tonic-gate 		    &last_str, sizeof (last_str)) != sizeof (last_str))
394*0Sstevel@tonic-gate 			last_str = envp_null;
395*0Sstevel@tonic-gate 		else {
396*0Sstevel@tonic-gate 			last_str += offset;
397*0Sstevel@tonic-gate 			if (last_str < (char *)envp ||
398*0Sstevel@tonic-gate 			    last_str >= (char *)envp + esize)
399*0Sstevel@tonic-gate 				last_str = envp_null;
400*0Sstevel@tonic-gate 		}
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 		/*
403*0Sstevel@tonic-gate 		 * Relocate the envp[] addresses, while ensuring that we
404*0Sstevel@tonic-gate 		 * don't return bad addresses.
405*0Sstevel@tonic-gate 		 */
406*0Sstevel@tonic-gate 		for (i = 0; envp[i] != NULL; i++) {
407*0Sstevel@tonic-gate 			str = (envp[i] += offset);
408*0Sstevel@tonic-gate 			if (str < (char *)envp || str >= (char *)envp + esize) {
409*0Sstevel@tonic-gate 				if (last_str != envp_null)
410*0Sstevel@tonic-gate 					envp[i] = last_str +
411*0Sstevel@tonic-gate 					    strlen(last_str) + 1;
412*0Sstevel@tonic-gate 				else
413*0Sstevel@tonic-gate 					envp[i] = envp_null;
414*0Sstevel@tonic-gate 			}
415*0Sstevel@tonic-gate 			last_str = envp[i];
416*0Sstevel@tonic-gate 		}
417*0Sstevel@tonic-gate 		envp[i] = NULL;
418*0Sstevel@tonic-gate 		*env = envp;
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	return (0);
422*0Sstevel@tonic-gate }
423