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 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 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