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