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 /* Copyright (c) 1988 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.6 */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/param.h> 35*0Sstevel@tonic-gate #include <sys/sysmacros.h> 36*0Sstevel@tonic-gate #include <sys/signal.h> 37*0Sstevel@tonic-gate #include <sys/cred.h> 38*0Sstevel@tonic-gate #include <sys/user.h> 39*0Sstevel@tonic-gate #include <sys/errno.h> 40*0Sstevel@tonic-gate #include <sys/vnode.h> 41*0Sstevel@tonic-gate #include <sys/proc.h> 42*0Sstevel@tonic-gate #include <sys/cmn_err.h> 43*0Sstevel@tonic-gate #include <sys/debug.h> 44*0Sstevel@tonic-gate #include <sys/pathname.h> 45*0Sstevel@tonic-gate #include <sys/disp.h> 46*0Sstevel@tonic-gate #include <sys/exec.h> 47*0Sstevel@tonic-gate #include <sys/kmem.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * This is the loadable module wrapper. 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate #include <sys/modctl.h> 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate extern int intpexec(); 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate static struct execsw esw = { 57*0Sstevel@tonic-gate intpmagicstr, 58*0Sstevel@tonic-gate 0, 59*0Sstevel@tonic-gate 2, 60*0Sstevel@tonic-gate intpexec, 61*0Sstevel@tonic-gate NULL 62*0Sstevel@tonic-gate }; 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate /* 65*0Sstevel@tonic-gate * Module linkage information for the kernel. 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate extern struct mod_ops mod_execops; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate static struct modlexec modlexec = { 70*0Sstevel@tonic-gate &mod_execops, "exec mod for interp", &esw 71*0Sstevel@tonic-gate }; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 74*0Sstevel@tonic-gate MODREV_1, (void *)&modlexec, NULL 75*0Sstevel@tonic-gate }; 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate int 78*0Sstevel@tonic-gate _init() 79*0Sstevel@tonic-gate { 80*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate int 84*0Sstevel@tonic-gate _fini() 85*0Sstevel@tonic-gate { 86*0Sstevel@tonic-gate return (mod_remove(&modlinkage)); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate int 90*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 91*0Sstevel@tonic-gate { 92*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * Crack open a '#!' line. 98*0Sstevel@tonic-gate */ 99*0Sstevel@tonic-gate static int 100*0Sstevel@tonic-gate getintphead(struct vnode *vp, struct intpdata *idatap) 101*0Sstevel@tonic-gate { 102*0Sstevel@tonic-gate int error; 103*0Sstevel@tonic-gate char *cp, *linep = idatap->intp; 104*0Sstevel@tonic-gate ssize_t resid; 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* 107*0Sstevel@tonic-gate * Read the entire line and confirm that it starts with '#!'. 108*0Sstevel@tonic-gate */ 109*0Sstevel@tonic-gate if (error = vn_rdwr(UIO_READ, vp, linep, INTPSZ, (offset_t)0, 110*0Sstevel@tonic-gate UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) 111*0Sstevel@tonic-gate return (error); 112*0Sstevel@tonic-gate if (resid > INTPSZ-2 || linep[0] != '#' || linep[1] != '!') 113*0Sstevel@tonic-gate return (ENOEXEC); 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * Blank all white space and find the newline. 116*0Sstevel@tonic-gate */ 117*0Sstevel@tonic-gate for (cp = &linep[2]; cp < &linep[INTPSZ] && *cp != '\n'; cp++) 118*0Sstevel@tonic-gate if (*cp == '\t') 119*0Sstevel@tonic-gate *cp = ' '; 120*0Sstevel@tonic-gate if (cp >= &linep[INTPSZ]) 121*0Sstevel@tonic-gate return (ENOEXEC); 122*0Sstevel@tonic-gate ASSERT(*cp == '\n'); 123*0Sstevel@tonic-gate *cp = '\0'; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * Locate the beginning and end of the interpreter name. 127*0Sstevel@tonic-gate * In addition to the name, one additional argument may 128*0Sstevel@tonic-gate * optionally be included here, to be prepended to the 129*0Sstevel@tonic-gate * arguments provided on the command line. Thus, for 130*0Sstevel@tonic-gate * example, you can say 131*0Sstevel@tonic-gate * 132*0Sstevel@tonic-gate * #! /usr/bin/awk -f 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate for (cp = &linep[2]; *cp == ' '; cp++) 135*0Sstevel@tonic-gate ; 136*0Sstevel@tonic-gate if (*cp == '\0') 137*0Sstevel@tonic-gate return (ENOEXEC); 138*0Sstevel@tonic-gate idatap->intp_name = cp; 139*0Sstevel@tonic-gate while (*cp && *cp != ' ') 140*0Sstevel@tonic-gate cp++; 141*0Sstevel@tonic-gate if (*cp == '\0') 142*0Sstevel@tonic-gate idatap->intp_arg = NULL; 143*0Sstevel@tonic-gate else { 144*0Sstevel@tonic-gate *cp++ = '\0'; 145*0Sstevel@tonic-gate while (*cp == ' ') 146*0Sstevel@tonic-gate cp++; 147*0Sstevel@tonic-gate if (*cp == '\0') 148*0Sstevel@tonic-gate idatap->intp_arg = NULL; 149*0Sstevel@tonic-gate else { 150*0Sstevel@tonic-gate idatap->intp_arg = cp; 151*0Sstevel@tonic-gate while (*cp && *cp != ' ') 152*0Sstevel@tonic-gate cp++; 153*0Sstevel@tonic-gate *cp = '\0'; 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate return (0); 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate int 160*0Sstevel@tonic-gate intpexec( 161*0Sstevel@tonic-gate struct vnode *vp, 162*0Sstevel@tonic-gate struct execa *uap, 163*0Sstevel@tonic-gate struct uarg *args, 164*0Sstevel@tonic-gate struct intpdata *idatap, 165*0Sstevel@tonic-gate int level, 166*0Sstevel@tonic-gate long *execsz, 167*0Sstevel@tonic-gate int setid, 168*0Sstevel@tonic-gate caddr_t exec_file, 169*0Sstevel@tonic-gate struct cred *cred) 170*0Sstevel@tonic-gate { 171*0Sstevel@tonic-gate vnode_t *nvp; 172*0Sstevel@tonic-gate int error = 0; 173*0Sstevel@tonic-gate struct intpdata idata; 174*0Sstevel@tonic-gate struct pathname intppn; 175*0Sstevel@tonic-gate struct pathname resolvepn; 176*0Sstevel@tonic-gate char *opath; 177*0Sstevel@tonic-gate char devfd[14]; 178*0Sstevel@tonic-gate int fd = -1; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if (level) { /* Can't recurse */ 181*0Sstevel@tonic-gate error = ENOEXEC; 182*0Sstevel@tonic-gate goto bad; 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate ASSERT(idatap == (struct intpdata *)NULL); 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * Allocate a buffer to read in the interpreter pathname. 189*0Sstevel@tonic-gate */ 190*0Sstevel@tonic-gate idata.intp = kmem_alloc(INTPSZ, KM_SLEEP); 191*0Sstevel@tonic-gate if (error = getintphead(vp, &idata)) 192*0Sstevel@tonic-gate goto fail; 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate * Look the new vnode up. 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate if (error = pn_get(idata.intp_name, UIO_SYSSPACE, &intppn)) 198*0Sstevel@tonic-gate goto fail; 199*0Sstevel@tonic-gate pn_alloc(&resolvepn); 200*0Sstevel@tonic-gate if (error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp)) { 201*0Sstevel@tonic-gate pn_free(&resolvepn); 202*0Sstevel@tonic-gate pn_free(&intppn); 203*0Sstevel@tonic-gate goto fail; 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate opath = args->pathname; 206*0Sstevel@tonic-gate args->pathname = resolvepn.pn_path; 207*0Sstevel@tonic-gate /* don't free resolvepn until we are done with args */ 208*0Sstevel@tonic-gate pn_free(&intppn); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate if (setid) { /* close security hole */ 211*0Sstevel@tonic-gate (void) strcpy(devfd, "/dev/fd/"); 212*0Sstevel@tonic-gate if (error = execopen(&vp, &fd)) 213*0Sstevel@tonic-gate goto done; 214*0Sstevel@tonic-gate numtos(fd, &devfd[8]); 215*0Sstevel@tonic-gate args->fname = devfd; 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate error = gexec(&nvp, uap, args, &idata, ++level, 219*0Sstevel@tonic-gate execsz, exec_file, cred); 220*0Sstevel@tonic-gate done: 221*0Sstevel@tonic-gate VN_RELE(nvp); 222*0Sstevel@tonic-gate args->pathname = opath; 223*0Sstevel@tonic-gate pn_free(&resolvepn); 224*0Sstevel@tonic-gate fail: 225*0Sstevel@tonic-gate kmem_free(idata.intp, INTPSZ); 226*0Sstevel@tonic-gate if (error && fd != -1) 227*0Sstevel@tonic-gate (void) execclose(fd); 228*0Sstevel@tonic-gate bad: 229*0Sstevel@tonic-gate return (error); 230*0Sstevel@tonic-gate } 231