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