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