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