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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2012 Milan Jurik. All rights reserved. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 31 /* from S5R4 1.6 */ 32 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/sysmacros.h> 36 #include <sys/signal.h> 37 #include <sys/cred.h> 38 #include <sys/user.h> 39 #include <sys/errno.h> 40 #include <sys/vnode.h> 41 #include <sys/proc.h> 42 #include <sys/cmn_err.h> 43 #include <sys/debug.h> 44 #include <sys/pathname.h> 45 #include <sys/disp.h> 46 #include <sys/exec.h> 47 #include <sys/kmem.h> 48 #include <sys/note.h> 49 #include <sys/sdt.h> 50 51 /* 52 * This is the loadable module wrapper. 53 */ 54 #include <sys/modctl.h> 55 56 extern int intpexec(struct vnode *, struct execa *, struct uarg *, 57 struct intpdata *, int, long *, int, caddr_t, struct cred *, int); 58 59 static struct execsw esw = { 60 intpmagicstr, 61 0, 62 2, 63 intpexec, 64 NULL 65 }; 66 67 /* 68 * Module linkage information for the kernel. 69 */ 70 extern struct mod_ops mod_execops; 71 72 static struct modlexec modlexec = { 73 &mod_execops, "exec mod for interp", &esw 74 }; 75 76 static struct modlinkage modlinkage = { 77 MODREV_1, { (void *)&modlexec, NULL } 78 }; 79 80 int 81 _init() 82 { 83 return (mod_install(&modlinkage)); 84 } 85 86 int 87 _fini() 88 { 89 return (mod_remove(&modlinkage)); 90 } 91 92 int 93 _info(struct modinfo *modinfop) 94 { 95 return (mod_info(&modlinkage, modinfop)); 96 } 97 98 99 /* 100 * Crack open a '#!' line. 101 */ 102 static int 103 getintphead(struct vnode *vp, struct intpdata *idatap) 104 { 105 int error; 106 char *cp, *linep = idatap->intp; 107 ssize_t resid; 108 109 /* 110 * Read the entire line and confirm that it starts with '#!'. 111 */ 112 if (error = vn_rdwr(UIO_READ, vp, linep, INTPSZ, (offset_t)0, 113 UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid)) 114 return (error); 115 if (resid > INTPSZ-2 || linep[0] != '#' || linep[1] != '!') 116 return (ENOEXEC); 117 /* 118 * Blank all white space and find the newline. 119 */ 120 for (cp = &linep[2]; cp < &linep[INTPSZ] && *cp != '\n'; cp++) 121 if (*cp == '\t') 122 *cp = ' '; 123 if (cp >= &linep[INTPSZ]) 124 return (ENOEXEC); 125 ASSERT(*cp == '\n'); 126 *cp = '\0'; 127 128 /* 129 * Locate the beginning and end of the interpreter name. 130 * In addition to the name, one additional argument may 131 * optionally be included here, to be prepended to the 132 * arguments provided on the command line. Thus, for 133 * example, you can say 134 * 135 * #! /usr/bin/awk -f 136 */ 137 for (cp = &linep[2]; *cp == ' '; cp++) 138 ; 139 if (*cp == '\0') 140 return (ENOEXEC); 141 idatap->intp_name[0] = cp; 142 while (*cp && *cp != ' ') 143 cp++; 144 if (*cp == '\0') { 145 idatap->intp_arg[0] = NULL; 146 } else { 147 *cp++ = '\0'; 148 while (*cp == ' ') 149 cp++; 150 if (*cp == '\0') 151 idatap->intp_arg[0] = NULL; 152 else { 153 idatap->intp_arg[0] = cp; 154 while (*cp && *cp != ' ') 155 cp++; 156 *cp = '\0'; 157 } 158 } 159 return (0); 160 } 161 162 /* 163 * We support nested interpreters up to a depth of INTP_MAXDEPTH (this value 164 * matches the depth on Linux). When a nested interpreter is in use, the 165 * previous name and argument must be passed along. We use the intpdata_t 166 * name and argument arrays for this. In the normal, non-nested case, only the 167 * first element in those arrays will be populated. 168 * 169 * For setid scripts the "script hole" is a security race condition between 170 * when we exec the interpreter and when the interpreter reads the script. We 171 * handle this below for the initial script, but we don't allow setid scripts 172 * when using nested interpreters. Because gexec only modifies the credentials 173 * for a setid script at level 0, then if we come back through for a nested 174 * interpreter we know that args->fname will be set (the first script is setid) 175 * and we can return an error. If an intermediate nested interpreter is setid 176 * then it will not be run with different credentials because of the gexec 177 * handling, so it is effectively no longer setid and we don't have to worry 178 * about the "script hole". 179 */ 180 int 181 intpexec( 182 struct vnode *vp, 183 struct execa *uap, 184 struct uarg *args, 185 struct intpdata *idatap, 186 int level, 187 long *execsz, 188 int setid, 189 caddr_t exec_file, 190 struct cred *cred, 191 int brand_action) 192 { 193 _NOTE(ARGUNUSED(brand_action)) 194 vnode_t *nvp; 195 int error = 0; 196 struct intpdata idata; 197 struct pathname intppn; 198 struct pathname resolvepn; 199 char *opath; 200 char devfd[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */ 201 int fd = -1; 202 203 if (level >= INTP_MAXDEPTH) { /* Can't recurse past maxdepth */ 204 error = ELOOP; 205 goto bad; 206 } 207 208 if (level == 0) 209 ASSERT(idatap == (struct intpdata *)NULL); 210 211 bzero(&idata, sizeof (intpdata_t)); 212 213 /* 214 * Allocate a buffer to read in the interpreter pathname. 215 */ 216 idata.intp = kmem_alloc(INTPSZ, KM_SLEEP); 217 if (error = getintphead(vp, &idata)) 218 goto fail; 219 220 /* 221 * Look the new vnode up. 222 */ 223 if (error = pn_get(idata.intp_name[0], UIO_SYSSPACE, &intppn)) 224 goto fail; 225 pn_alloc(&resolvepn); 226 if (error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp)) { 227 pn_free(&resolvepn); 228 pn_free(&intppn); 229 goto fail; 230 } 231 232 if (level > 0) { 233 /* 234 * We have a nested interpreter. The previous name(s) and 235 * argument(s) need to be passed along. We also keep track 236 * of how often this zone uses nested interpreters. 237 */ 238 int i; 239 240 atomic_inc_32(&curproc->p_zone->zone_nested_intp); 241 242 ASSERT(idatap != NULL); 243 /* since we're shifting up, loop stops one short */ 244 for (i = 0; i < (INTP_MAXDEPTH - 1); i++) { 245 idata.intp_name[i + 1] = idatap->intp_name[i]; 246 idata.intp_arg[i + 1] = idatap->intp_arg[i]; 247 } 248 249 DTRACE_PROBE3(nested__intp, int, level, void *, &idata, 250 void *, nvp); 251 } 252 253 opath = args->pathname; 254 args->pathname = resolvepn.pn_path; 255 /* don't free resolvepn until we are done with args */ 256 pn_free(&intppn); 257 258 /* 259 * Disallow setuid or additional privilege execution for nested 260 * interpreters. 261 */ 262 if (level > 0 && args->fname != NULL) { 263 error = ENOEXEC; 264 goto done; 265 } 266 267 /* 268 * When we're executing a set-uid script resulting in uids 269 * mismatching or when we execute with additional privileges, 270 * we close the "replace script between exec and open by shell" 271 * hole by passing the script as /dev/fd parameter. 272 */ 273 if ((setid & EXECSETID_PRIVS) != 0 || 274 (setid & (EXECSETID_UGIDS|EXECSETID_SETID)) == 275 (EXECSETID_UGIDS|EXECSETID_SETID)) { 276 (void) strcpy(devfd, "/dev/fd/"); 277 if (error = execopen(&vp, &fd)) 278 goto done; 279 numtos(fd, &devfd[8]); 280 args->fname = devfd; 281 } 282 283 error = gexec(&nvp, uap, args, &idata, ++level, execsz, exec_file, cred, 284 EBA_NONE); 285 286 if (!error) { 287 /* 288 * Close this executable as the interpreter 289 * will open and close it later on. 290 */ 291 (void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, cred, NULL); 292 } 293 done: 294 VN_RELE(nvp); 295 args->pathname = opath; 296 pn_free(&resolvepn); 297 fail: 298 kmem_free(idata.intp, INTPSZ); 299 if (error && fd != -1) 300 (void) execclose(fd); 301 bad: 302 return (error); 303 }