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