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