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
kvm_getcmd32(kvm_t * kd,struct proc * p,struct user * u,char *** arg,char *** env)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
kvm_getcmd(kvm_t * kd,struct proc * proc,struct user * u,char *** arg,char *** env)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