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 1990-2003 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 <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/param.h> 31*0Sstevel@tonic-gate #include <sys/systm.h> 32*0Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 33*0Sstevel@tonic-gate #include <sys/sysmacros.h> 34*0Sstevel@tonic-gate #include <sys/signal.h> 35*0Sstevel@tonic-gate #include <sys/cred.h> 36*0Sstevel@tonic-gate #include <sys/user.h> 37*0Sstevel@tonic-gate #include <sys/errno.h> 38*0Sstevel@tonic-gate #include <sys/vnode.h> 39*0Sstevel@tonic-gate #include <sys/mman.h> 40*0Sstevel@tonic-gate #include <sys/kmem.h> 41*0Sstevel@tonic-gate #include <sys/proc.h> 42*0Sstevel@tonic-gate #include <sys/pathname.h> 43*0Sstevel@tonic-gate #include <sys/cmn_err.h> 44*0Sstevel@tonic-gate #include <sys/debug.h> 45*0Sstevel@tonic-gate #include <sys/exec.h> 46*0Sstevel@tonic-gate #include <sys/exechdr.h> 47*0Sstevel@tonic-gate #include <sys/auxv.h> 48*0Sstevel@tonic-gate #include <sys/core.h> 49*0Sstevel@tonic-gate #include <sys/vmparam.h> 50*0Sstevel@tonic-gate #include <sys/archsystm.h> 51*0Sstevel@tonic-gate #include <sys/fs/swapnode.h> 52*0Sstevel@tonic-gate #include <sys/modctl.h> 53*0Sstevel@tonic-gate #include <vm/anon.h> 54*0Sstevel@tonic-gate #include <vm/as.h> 55*0Sstevel@tonic-gate #include <vm/seg.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate static int aoutexec(vnode_t *vp, execa_t *uap, uarg_t *args, 58*0Sstevel@tonic-gate intpdata_t *idatap, int level, long *execsz, int setid, 59*0Sstevel@tonic-gate caddr_t exec_file, cred_t *cred); 60*0Sstevel@tonic-gate static int get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz, 61*0Sstevel@tonic-gate int *isdyn); 62*0Sstevel@tonic-gate static int aoutcore(vnode_t *vp, proc_t *pp, cred_t *credp, 63*0Sstevel@tonic-gate rlim64_t rlimit, int sig, core_content_t content); 64*0Sstevel@tonic-gate #ifdef _LP64 65*0Sstevel@tonic-gate extern int elf32exec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int, 66*0Sstevel@tonic-gate long *, int, caddr_t, cred_t *); 67*0Sstevel@tonic-gate extern int elf32core(vnode_t *, proc_t *, cred_t *, rlim64_t, int, 68*0Sstevel@tonic-gate core_content_t); 69*0Sstevel@tonic-gate #else /* _LP64 */ 70*0Sstevel@tonic-gate extern int elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int, 71*0Sstevel@tonic-gate long *, int, caddr_t, cred_t *); 72*0Sstevel@tonic-gate extern int elfcore(vnode_t *, proc_t *, cred_t *, rlim64_t, int, 73*0Sstevel@tonic-gate core_content_t); 74*0Sstevel@tonic-gate #endif /* _LP64 */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate char _depends_on[] = "exec/elfexec"; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate static struct execsw nesw = { 79*0Sstevel@tonic-gate aout_nmagicstr, 80*0Sstevel@tonic-gate 2, 81*0Sstevel@tonic-gate 2, 82*0Sstevel@tonic-gate aoutexec, 83*0Sstevel@tonic-gate aoutcore 84*0Sstevel@tonic-gate }; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate static struct execsw zesw = { 87*0Sstevel@tonic-gate aout_zmagicstr, 88*0Sstevel@tonic-gate 2, 89*0Sstevel@tonic-gate 2, 90*0Sstevel@tonic-gate aoutexec, 91*0Sstevel@tonic-gate aoutcore 92*0Sstevel@tonic-gate }; 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate static struct execsw oesw = { 95*0Sstevel@tonic-gate aout_omagicstr, 96*0Sstevel@tonic-gate 2, 97*0Sstevel@tonic-gate 2, 98*0Sstevel@tonic-gate aoutexec, 99*0Sstevel@tonic-gate aoutcore 100*0Sstevel@tonic-gate }; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate /* 103*0Sstevel@tonic-gate * Module linkage information for the kernel. 104*0Sstevel@tonic-gate */ 105*0Sstevel@tonic-gate static struct modlexec nexec = { 106*0Sstevel@tonic-gate &mod_execops, "exec for NMAGIC", &nesw 107*0Sstevel@tonic-gate }; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate static struct modlexec zexec = { 110*0Sstevel@tonic-gate &mod_execops, "exec for ZMAGIC", &zesw 111*0Sstevel@tonic-gate }; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate static struct modlexec oexec = { 114*0Sstevel@tonic-gate &mod_execops, "exec for OMAGIC", &oesw 115*0Sstevel@tonic-gate }; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 118*0Sstevel@tonic-gate MODREV_1, &nexec, &zexec, &oexec, NULL 119*0Sstevel@tonic-gate }; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate int 122*0Sstevel@tonic-gate _init(void) 123*0Sstevel@tonic-gate { 124*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate int 128*0Sstevel@tonic-gate _fini(void) 129*0Sstevel@tonic-gate { 130*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate int 134*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 135*0Sstevel@tonic-gate { 136*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate /*ARGSUSED*/ 141*0Sstevel@tonic-gate static int 142*0Sstevel@tonic-gate aoutexec(vnode_t *vp, struct execa *uap, struct uarg *args, 143*0Sstevel@tonic-gate struct intpdata *idatap, int level, long *execsz, int setid, 144*0Sstevel@tonic-gate caddr_t exec_file, cred_t *cred) 145*0Sstevel@tonic-gate { 146*0Sstevel@tonic-gate int error; 147*0Sstevel@tonic-gate struct exdata edp, edpout; 148*0Sstevel@tonic-gate struct execenv exenv; 149*0Sstevel@tonic-gate proc_t *pp = ttoproc(curthread); 150*0Sstevel@tonic-gate struct vnode *nvp; 151*0Sstevel@tonic-gate int pagetext, pagedata; 152*0Sstevel@tonic-gate int dataprot = PROT_ALL; 153*0Sstevel@tonic-gate int textprot = PROT_ALL & ~PROT_WRITE; 154*0Sstevel@tonic-gate int isdyn; 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate args->to_model = DATAMODEL_ILP32; 157*0Sstevel@tonic-gate *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1); 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Read in and validate the file header. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate if (error = get_aout_head(&vp, &edp, execsz, &isdyn)) 163*0Sstevel@tonic-gate return (error); 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate if (error = chkaout(&edp)) 166*0Sstevel@tonic-gate return (error); 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate /* 169*0Sstevel@tonic-gate * Take a quick look to see if it looks like we will have 170*0Sstevel@tonic-gate * enough swap space for the program to get started. This 171*0Sstevel@tonic-gate * is not a guarantee that we will succeed, but it is definitely 172*0Sstevel@tonic-gate * better than finding this out after we are committed to the 173*0Sstevel@tonic-gate * new memory image. Maybe what is needed is a way to "prereserve" 174*0Sstevel@tonic-gate * swap space for some segment mappings here. 175*0Sstevel@tonic-gate * 176*0Sstevel@tonic-gate * But with shared libraries the process can make it through 177*0Sstevel@tonic-gate * the exec only to have ld.so fail to get the program going 178*0Sstevel@tonic-gate * because its mmap's will not be able to succeed if the system 179*0Sstevel@tonic-gate * is running low on swap space. In fact this is a far more 180*0Sstevel@tonic-gate * common failure mode, but we cannot do much about this here 181*0Sstevel@tonic-gate * other than add some slop to our anonymous memory resources 182*0Sstevel@tonic-gate * requirements estimate based on some guess since we cannot know 183*0Sstevel@tonic-gate * what else the program will really need to get to a useful state. 184*0Sstevel@tonic-gate * 185*0Sstevel@tonic-gate * XXX - The stack size (clrnd(SSIZE + btopr(nargc))) should also 186*0Sstevel@tonic-gate * be used when checking for swap space. This requires some work 187*0Sstevel@tonic-gate * since nargc is actually determined in exec_args() which is done 188*0Sstevel@tonic-gate * after this check and hence we punt for now. 189*0Sstevel@tonic-gate * 190*0Sstevel@tonic-gate * nargc = SA(nc + (na + 4) * NBPW) + sizeof (struct rwindow); 191*0Sstevel@tonic-gate */ 192*0Sstevel@tonic-gate if (CURRENT_TOTAL_AVAILABLE_SWAP < btopr(edp.ux_dsize) + btopr(SSIZE)) 193*0Sstevel@tonic-gate return (ENOMEM); 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* 196*0Sstevel@tonic-gate * Load the trap 0 interpreter. 197*0Sstevel@tonic-gate */ 198*0Sstevel@tonic-gate if (error = lookupname("/usr/4lib/sbcp", UIO_SYSSPACE, FOLLOW, 199*0Sstevel@tonic-gate NULLVPP, &nvp)) { 200*0Sstevel@tonic-gate goto done; 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate #ifdef _LP64 203*0Sstevel@tonic-gate if (error = elf32exec(nvp, uap, args, idatap, level, execsz, 204*0Sstevel@tonic-gate setid, exec_file, cred)) 205*0Sstevel@tonic-gate #else /* _LP64 */ 206*0Sstevel@tonic-gate if (error = elfexec(nvp, uap, args, idatap, level, execsz, 207*0Sstevel@tonic-gate setid, exec_file, cred)) 208*0Sstevel@tonic-gate #endif /* _LP64 */ 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate VN_RELE(nvp); 211*0Sstevel@tonic-gate return (error); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate VN_RELE(nvp); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate /* 216*0Sstevel@tonic-gate * Determine the a.out's characteristics. 217*0Sstevel@tonic-gate */ 218*0Sstevel@tonic-gate getexinfo(&edp, &edpout, &pagetext, &pagedata); 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate /* 221*0Sstevel@tonic-gate * Load the a.out's text and data. 222*0Sstevel@tonic-gate */ 223*0Sstevel@tonic-gate if (error = execmap(edp.vp, edp.ux_txtorg, edp.ux_tsize, 224*0Sstevel@tonic-gate (size_t)0, edp.ux_toffset, textprot, pagetext, 0)) 225*0Sstevel@tonic-gate goto done; 226*0Sstevel@tonic-gate if (error = execmap(edp.vp, edp.ux_datorg, edp.ux_dsize, 227*0Sstevel@tonic-gate edp.ux_bsize, edp.ux_doffset, dataprot, pagedata, 0)) 228*0Sstevel@tonic-gate goto done; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate exenv.ex_brkbase = (caddr_t)edp.ux_datorg; 231*0Sstevel@tonic-gate exenv.ex_brksize = edp.ux_dsize + edp.ux_bsize; 232*0Sstevel@tonic-gate exenv.ex_magic = edp.ux_mag; 233*0Sstevel@tonic-gate exenv.ex_vp = edp.vp; 234*0Sstevel@tonic-gate setexecenv(&exenv); 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate done: 237*0Sstevel@tonic-gate if (error != 0) 238*0Sstevel@tonic-gate psignal(pp, SIGKILL); 239*0Sstevel@tonic-gate else { 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * Ensure that the max fds do not exceed 256 (this is 242*0Sstevel@tonic-gate * applicable to 4.x binaries, which is why we only 243*0Sstevel@tonic-gate * do it on a.out files). 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate struct rlimit64 fdno_rlim; 246*0Sstevel@tonic-gate rctl_alloc_gp_t *gp = rctl_rlimit_set_prealloc(1); 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 249*0Sstevel@tonic-gate (void) rctl_rlimit_get(rctlproc_legacy[RLIMIT_NOFILE], curproc, 250*0Sstevel@tonic-gate &fdno_rlim); 251*0Sstevel@tonic-gate if (fdno_rlim.rlim_cur > 256) { 252*0Sstevel@tonic-gate fdno_rlim.rlim_cur = fdno_rlim.rlim_max = 256; 253*0Sstevel@tonic-gate (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE], 254*0Sstevel@tonic-gate curproc, &fdno_rlim, gp, 255*0Sstevel@tonic-gate rctlproc_flags[RLIMIT_NOFILE], 256*0Sstevel@tonic-gate rctlproc_signals[RLIMIT_NOFILE], CRED()); 257*0Sstevel@tonic-gate } else if (fdno_rlim.rlim_max > 256) { 258*0Sstevel@tonic-gate fdno_rlim.rlim_max = 256; 259*0Sstevel@tonic-gate (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE], 260*0Sstevel@tonic-gate curproc, &fdno_rlim, gp, 261*0Sstevel@tonic-gate rctlproc_flags[RLIMIT_NOFILE], 262*0Sstevel@tonic-gate rctlproc_signals[RLIMIT_NOFILE], CRED()); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate rctl_prealloc_destroy(gp); 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate return (error); 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate /* 273*0Sstevel@tonic-gate * Read in and validate the file header. 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate static int 276*0Sstevel@tonic-gate get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz, int *isdyn) 277*0Sstevel@tonic-gate { 278*0Sstevel@tonic-gate struct vnode *vp = *vpp; 279*0Sstevel@tonic-gate struct exec filhdr; 280*0Sstevel@tonic-gate int error; 281*0Sstevel@tonic-gate ssize_t resid; 282*0Sstevel@tonic-gate rlim64_t limit; 283*0Sstevel@tonic-gate rlim64_t roundlimit; 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate if (error = vn_rdwr(UIO_READ, vp, (caddr_t)&filhdr, 286*0Sstevel@tonic-gate (ssize_t)sizeof (filhdr), (offset_t)0, UIO_SYSSPACE, 0, 287*0Sstevel@tonic-gate (rlim64_t)0, CRED(), &resid)) 288*0Sstevel@tonic-gate return (error); 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate if (resid != 0) 291*0Sstevel@tonic-gate return (ENOEXEC); 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate switch (filhdr.a_magic) { 294*0Sstevel@tonic-gate case OMAGIC: 295*0Sstevel@tonic-gate filhdr.a_data += filhdr.a_text; 296*0Sstevel@tonic-gate filhdr.a_text = 0; 297*0Sstevel@tonic-gate break; 298*0Sstevel@tonic-gate case ZMAGIC: 299*0Sstevel@tonic-gate case NMAGIC: 300*0Sstevel@tonic-gate break; 301*0Sstevel@tonic-gate default: 302*0Sstevel@tonic-gate return (ENOEXEC); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /* 306*0Sstevel@tonic-gate * Check total memory requirements (in pages) for a new process 307*0Sstevel@tonic-gate * against the available memory or upper limit of memory allowed. 308*0Sstevel@tonic-gate * 309*0Sstevel@tonic-gate * For the 64-bit kernel, the limit can be set large enough so that 310*0Sstevel@tonic-gate * rounding it up to a page can overflow, so we check for btopr() 311*0Sstevel@tonic-gate * overflowing here by comparing it with the unrounded limit in pages. 312*0Sstevel@tonic-gate */ 313*0Sstevel@tonic-gate *execsz += btopr(filhdr.a_text + filhdr.a_data); 314*0Sstevel@tonic-gate limit = btop(curproc->p_vmem_ctl); 315*0Sstevel@tonic-gate roundlimit = btopr(curproc->p_vmem_ctl); 316*0Sstevel@tonic-gate if ((roundlimit > limit && *execsz > roundlimit) || 317*0Sstevel@tonic-gate (roundlimit < limit && *execsz > limit)) { 318*0Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 319*0Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_VMEM], 320*0Sstevel@tonic-gate curproc->p_rctls, curproc, RCA_SAFE); 321*0Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 322*0Sstevel@tonic-gate return (ENOMEM); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate edp->ux_mach = filhdr.a_machtype; 326*0Sstevel@tonic-gate edp->ux_tsize = filhdr.a_text; 327*0Sstevel@tonic-gate edp->ux_dsize = filhdr.a_data; 328*0Sstevel@tonic-gate edp->ux_bsize = filhdr.a_bss; 329*0Sstevel@tonic-gate edp->ux_mag = filhdr.a_magic; 330*0Sstevel@tonic-gate edp->ux_toffset = gettfile(&filhdr); 331*0Sstevel@tonic-gate edp->ux_doffset = getdfile(&filhdr); 332*0Sstevel@tonic-gate edp->ux_txtorg = gettmem(&filhdr); 333*0Sstevel@tonic-gate edp->ux_datorg = getdmem(&filhdr); 334*0Sstevel@tonic-gate edp->ux_entloc = (caddr_t)filhdr.a_entry; 335*0Sstevel@tonic-gate edp->vp = vp; 336*0Sstevel@tonic-gate *isdyn = filhdr.a_dynamic; 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate return (0); 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate static int 342*0Sstevel@tonic-gate aoutcore(vnode_t *vp, proc_t *pp, struct cred *credp, rlim64_t rlimit, int sig, 343*0Sstevel@tonic-gate core_content_t content) 344*0Sstevel@tonic-gate { 345*0Sstevel@tonic-gate #ifdef _LP64 346*0Sstevel@tonic-gate return (elf32core(vp, pp, credp, rlimit, sig, content)); 347*0Sstevel@tonic-gate #else 348*0Sstevel@tonic-gate return (elfcore(vp, pp, credp, rlimit, sig, content)); 349*0Sstevel@tonic-gate #endif 350*0Sstevel@tonic-gate } 351