1 /* 2 * Copyright (c) 1993, David Greenman 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by David Greenman 16 * 4. The name of the developer may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $Id: kern_exec.c,v 1.4 1994/08/18 22:34:59 wollman Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/signalvar.h> 37 #include <sys/resourcevar.h> 38 #include <sys/kernel.h> 39 #include <sys/mount.h> 40 #include <sys/file.h> 41 #include <sys/acct.h> 42 #include <sys/exec.h> 43 #include <sys/imgact.h> 44 #include <sys/stat.h> 45 #include <sys/wait.h> 46 #include <sys/mman.h> 47 #include <sys/malloc.h> 48 #include <sys/syslog.h> 49 50 #include <vm/vm.h> 51 #include <vm/vm_kern.h> 52 53 #include <machine/reg.h> 54 55 int *exec_copyout_strings __P((struct image_params *)); 56 57 static int exec_check_permissions(struct image_params *); 58 59 /* 60 * execsw_set is constructed for us by the linker. Each of the items 61 * is a pointer to a `const struct execsw', hence the double pointer here. 62 */ 63 extern const struct linker_set execsw_set; 64 const struct execsw **execsw = (const struct execsw **)&execsw_set.ls_items[0]; 65 66 /* 67 * execve() system call. 68 */ 69 int 70 execve(p, uap, retval) 71 struct proc *p; 72 register struct execve_args *uap; 73 int *retval; 74 { 75 struct nameidata nd, *ndp; 76 char *stringbase, *stringp; 77 int *stack_base; 78 int error, resid, len, i; 79 struct image_params image_params, *iparams; 80 struct vnode *vnodep; 81 struct vattr attr; 82 char *image_header; 83 84 iparams = &image_params; 85 bzero((caddr_t)iparams, sizeof(struct image_params)); 86 image_header = (char *)0; 87 88 /* 89 * Initialize a few constants in the common area 90 */ 91 iparams->proc = p; 92 iparams->uap = uap; 93 iparams->attr = &attr; 94 95 /* 96 * Allocate temporary demand zeroed space for argument and 97 * environment strings 98 */ 99 error = vm_allocate(kernel_map, (vm_offset_t *)&iparams->stringbase, 100 ARG_MAX, TRUE); 101 if (error) { 102 log(LOG_WARNING, "execve: failed to allocate string space\n"); 103 return (error); 104 } 105 106 if (!iparams->stringbase) { 107 error = ENOMEM; 108 goto exec_fail; 109 } 110 iparams->stringp = iparams->stringbase; 111 iparams->stringspace = ARG_MAX; 112 113 /* 114 * Translate the file name. namei() returns a vnode pointer 115 * in ni_vp amoung other things. 116 */ 117 ndp = &nd; 118 ndp->ni_cnd.cn_nameiop = LOOKUP; 119 ndp->ni_cnd.cn_flags = LOCKLEAF | FOLLOW | SAVENAME; 120 ndp->ni_cnd.cn_proc = curproc; 121 ndp->ni_cnd.cn_cred = curproc->p_cred->pc_ucred; 122 ndp->ni_segflg = UIO_USERSPACE; 123 ndp->ni_dirp = uap->fname; 124 125 interpret: 126 127 error = namei(ndp); 128 if (error) { 129 vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase, 130 ARG_MAX); 131 goto exec_fail; 132 } 133 134 iparams->vnodep = vnodep = ndp->ni_vp; 135 136 if (vnodep == NULL) { 137 error = ENOEXEC; 138 goto exec_fail_dealloc; 139 } 140 141 /* 142 * Check file permissions (also 'opens' file) 143 */ 144 error = exec_check_permissions(iparams); 145 if (error) 146 goto exec_fail_dealloc; 147 148 /* 149 * Map the image header (first page) of the file into 150 * kernel address space 151 */ 152 error = vm_mmap(kernel_map, /* map */ 153 (vm_offset_t *)&image_header, /* address */ 154 PAGE_SIZE, /* size */ 155 VM_PROT_READ, /* protection */ 156 VM_PROT_READ, /* max protection */ 157 0, /* flags */ 158 (caddr_t)vnodep, /* vnode */ 159 0); /* offset */ 160 if (error) { 161 uprintf("mmap failed: %d\n",error); 162 goto exec_fail_dealloc; 163 } 164 iparams->image_header = image_header; 165 166 /* 167 * Loop through list of image activators, calling each one. 168 * If there is no match, the activator returns -1. If there 169 * is a match, but there was an error during the activation, 170 * the error is returned. Otherwise 0 means success. If the 171 * image is interpreted, loop back up and try activating 172 * the interpreter. 173 */ 174 for (i = 0; execsw[i]; ++i) { 175 if (execsw[i]->ex_imgact) 176 error = (*execsw[i]->ex_imgact)(iparams); 177 else 178 continue; 179 180 if (error == -1) 181 continue; 182 if (error) 183 goto exec_fail_dealloc; 184 if (iparams->interpreted) { 185 /* free old vnode and name buffer */ 186 vput(ndp->ni_vp); 187 FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI); 188 if (vm_deallocate(kernel_map, 189 (vm_offset_t)image_header, PAGE_SIZE)) 190 panic("execve: header dealloc failed (1)"); 191 192 /* set new name to that of the interpreter */ 193 ndp->ni_segflg = UIO_SYSSPACE; 194 ndp->ni_dirp = iparams->interpreter_name; 195 ndp->ni_cnd.cn_nameiop = LOOKUP; 196 ndp->ni_cnd.cn_flags = LOCKLEAF | FOLLOW | SAVENAME; 197 ndp->ni_cnd.cn_proc = curproc; 198 ndp->ni_cnd.cn_cred = curproc->p_cred->pc_ucred; 199 goto interpret; 200 } 201 break; 202 } 203 /* If we made it through all the activators and none matched, exit. */ 204 if (error == -1) { 205 error = ENOEXEC; 206 goto exec_fail_dealloc; 207 } 208 209 /* 210 * Copy out strings (args and env) and initialize stack base 211 */ 212 stack_base = exec_copyout_strings(iparams); 213 p->p_vmspace->vm_minsaddr = (char *)stack_base; 214 215 /* 216 * Stuff argument count as first item on stack 217 */ 218 *(--stack_base) = iparams->argc; 219 220 /* close files on exec */ 221 fdcloseexec(p); 222 223 /* reset caught signals */ 224 execsigs(p); 225 226 /* name this process - nameiexec(p, ndp) */ 227 len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN); 228 bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len); 229 p->p_comm[len] = 0; 230 231 /* 232 * mark as executable, wakeup any process that was vforked and tell 233 * it that it now has it's own resources back 234 */ 235 p->p_flag |= P_EXEC; 236 if (p->p_pptr && (p->p_flag & P_PPWAIT)) { 237 p->p_flag &= ~P_PPWAIT; 238 wakeup((caddr_t)p->p_pptr); 239 } 240 241 /* implement set userid/groupid */ 242 p->p_flag &= ~P_SUGID; 243 244 /* 245 * Turn off kernel tracing for set-id programs, except for 246 * root. 247 */ 248 if (p->p_tracep && (attr.va_mode & (VSUID | VSGID)) && 249 suser(p->p_ucred, &p->p_acflag)) { 250 p->p_traceflag = 0; 251 vrele(p->p_tracep); 252 p->p_tracep = 0; 253 } 254 if ((attr.va_mode & VSUID) && (p->p_flag & P_TRACED) == 0) { 255 p->p_ucred = crcopy(p->p_ucred); 256 p->p_ucred->cr_uid = attr.va_uid; 257 p->p_flag |= P_SUGID; 258 } 259 if ((attr.va_mode & VSGID) && (p->p_flag & P_TRACED) == 0) { 260 p->p_ucred = crcopy(p->p_ucred); 261 p->p_ucred->cr_groups[0] = attr.va_gid; 262 p->p_flag |= P_SUGID; 263 } 264 265 /* 266 * Implement correct POSIX saved uid behavior. 267 */ 268 p->p_cred->p_svuid = p->p_ucred->cr_uid; 269 p->p_cred->p_svgid = p->p_ucred->cr_gid; 270 271 /* mark vnode pure text */ 272 ndp->ni_vp->v_flag |= VTEXT; 273 274 /* 275 * If tracing the process, trap to debugger so breakpoints 276 * can be set before the program executes. 277 */ 278 if (p->p_flag & P_TRACED) 279 psignal(p, SIGTRAP); 280 281 /* clear "fork but no exec" flag, as we _are_ execing */ 282 p->p_acflag &= ~AFORK; 283 284 /* Set entry address */ 285 setregs(p, iparams->entry_addr, stack_base); 286 287 /* 288 * free various allocated resources 289 */ 290 if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase, ARG_MAX)) 291 panic("execve: string buffer dealloc failed (1)"); 292 if (vm_deallocate(kernel_map, (vm_offset_t)image_header, PAGE_SIZE)) 293 panic("execve: header dealloc failed (2)"); 294 vput(ndp->ni_vp); 295 FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI); 296 297 return (0); 298 299 exec_fail_dealloc: 300 if (iparams->stringbase && iparams->stringbase != (char *)-1) 301 if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase, 302 ARG_MAX)) 303 panic("execve: string buffer dealloc failed (2)"); 304 if (iparams->image_header && iparams->image_header != (char *)-1) 305 if (vm_deallocate(kernel_map, 306 (vm_offset_t)iparams->image_header, PAGE_SIZE)) 307 panic("execve: header dealloc failed (3)"); 308 vput(ndp->ni_vp); 309 FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI); 310 311 exec_fail: 312 if (iparams->vmspace_destroyed) { 313 /* sorry, no more process anymore. exit gracefully */ 314 #if 0 /* XXX */ 315 vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ); 316 #endif 317 exit1(p, W_EXITCODE(0, SIGABRT)); 318 /* NOT REACHED */ 319 return(0); 320 } else { 321 return(error); 322 } 323 } 324 325 /* 326 * Destroy old address space, and allocate a new stack 327 * The new stack is only SGROWSIZ large because it is grown 328 * automatically in trap.c. 329 */ 330 int 331 exec_new_vmspace(iparams) 332 struct image_params *iparams; 333 { 334 int error; 335 struct vmspace *vmspace = iparams->proc->p_vmspace; 336 caddr_t stack_addr = (caddr_t) (USRSTACK - SGROWSIZ); 337 338 iparams->vmspace_destroyed = 1; 339 340 /* Blow away entire process VM */ 341 vm_deallocate(&vmspace->vm_map, 0, USRSTACK); 342 343 /* Allocate a new stack */ 344 error = vm_allocate(&vmspace->vm_map, (vm_offset_t *)&stack_addr, 345 SGROWSIZ, FALSE); 346 if (error) 347 return(error); 348 349 vmspace->vm_ssize = SGROWSIZ >> PAGE_SHIFT; 350 351 /* Initialize maximum stack address */ 352 vmspace->vm_maxsaddr = (char *)USRSTACK - MAXSSIZ; 353 354 return(0); 355 } 356 357 /* 358 * Copy out argument and environment strings from the old process 359 * address space into the temporary string buffer. 360 */ 361 int 362 exec_extract_strings(iparams) 363 struct image_params *iparams; 364 { 365 char **argv, **envv; 366 char *argp, *envp; 367 int error, length; 368 369 /* 370 * extract arguments first 371 */ 372 373 argv = iparams->uap->argv; 374 375 if (argv) { 376 while (argp = (caddr_t) fuword(argv++)) { 377 if (argp == (caddr_t) -1) 378 return (EFAULT); 379 if (error = copyinstr(argp, iparams->stringp, 380 iparams->stringspace, &length)) { 381 if (error == ENAMETOOLONG) 382 return(E2BIG); 383 return (error); 384 } 385 iparams->stringspace -= length; 386 iparams->stringp += length; 387 iparams->argc++; 388 } 389 } 390 391 /* 392 * extract environment strings 393 */ 394 395 envv = iparams->uap->envv; 396 397 if (envv) { 398 while (envp = (caddr_t) fuword(envv++)) { 399 if (envp == (caddr_t) -1) 400 return (EFAULT); 401 if (error = copyinstr(envp, iparams->stringp, 402 iparams->stringspace, &length)) { 403 if (error == ENAMETOOLONG) 404 return(E2BIG); 405 return (error); 406 } 407 iparams->stringspace -= length; 408 iparams->stringp += length; 409 iparams->envc++; 410 } 411 } 412 413 return (0); 414 } 415 416 /* 417 * Copy strings out to the new process address space, constructing 418 * new arg and env vector tables. Return a pointer to the base 419 * so that it can be used as the initial stack pointer. 420 */ 421 int * 422 exec_copyout_strings(iparams) 423 struct image_params *iparams; 424 { 425 int argc, envc; 426 char **vectp; 427 char *stringp, *destp; 428 int *stack_base; 429 int vect_table_size, string_table_size; 430 struct ps_strings *arginfo; 431 432 /* 433 * Calculate string base and vector table pointers. 434 */ 435 arginfo = PS_STRINGS; 436 destp = (caddr_t)arginfo - roundup((ARG_MAX - iparams->stringspace), sizeof(char *)); 437 /* 438 * The '+ 2' is for the null pointers at the end of each of the 439 * arg and env vector sets 440 */ 441 vectp = (char **) (destp - 442 (iparams->argc + iparams->envc + 2) * sizeof(char *)); 443 444 /* 445 * vectp also becomes our initial stack base 446 */ 447 stack_base = (int *)vectp; 448 449 stringp = iparams->stringbase; 450 argc = iparams->argc; 451 envc = iparams->envc; 452 453 /* 454 * Fill in "ps_strings" struct for ps, w, etc. 455 */ 456 arginfo->ps_argvstr = destp; 457 arginfo->ps_nargvstr = argc; 458 459 /* 460 * Copy the arg strings and fill in vector table as we go. 461 */ 462 for (; argc > 0; --argc) { 463 *(vectp++) = destp; 464 while (*destp++ = *stringp++); 465 } 466 467 /* a null vector table pointer seperates the argp's from the envp's */ 468 *(vectp++) = NULL; 469 470 arginfo->ps_envstr = destp; 471 arginfo->ps_nenvstr = envc; 472 473 /* 474 * Copy the env strings and fill in vector table as we go. 475 */ 476 for (; envc > 0; --envc) { 477 *(vectp++) = destp; 478 while (*destp++ = *stringp++); 479 } 480 481 /* end of vector table is a null pointer */ 482 *vectp = NULL; 483 484 return (stack_base); 485 } 486 487 /* 488 * Check permissions of file to execute. 489 * Return 0 for success or error code on failure. 490 */ 491 static int 492 exec_check_permissions(iparams) 493 struct image_params *iparams; 494 { 495 struct proc *p = iparams->proc; 496 struct vnode *vnodep = iparams->vnodep; 497 struct vattr *attr = iparams->attr; 498 int error; 499 500 /* 501 * Check number of open-for-writes on the file and deny execution 502 * if there are any. 503 */ 504 if (vnodep->v_writecount) { 505 return (ETXTBSY); 506 } 507 508 /* Get file attributes */ 509 error = VOP_GETATTR(vnodep, attr, p->p_ucred, p); 510 if (error) 511 return (error); 512 513 /* 514 * 1) Check if file execution is disabled for the filesystem that this 515 * file resides on. 516 * 2) Insure that at least one execute bit is on - otherwise root 517 * will always succeed, and we don't want to happen unless the 518 * file really is executable. 519 * 3) Insure that the file is a regular file. 520 */ 521 if ((vnodep->v_mount->mnt_flag & MNT_NOEXEC) || 522 ((attr->va_mode & 0111) == 0) || 523 (attr->va_type != VREG)) { 524 return (EACCES); 525 } 526 527 /* 528 * Zero length files can't be exec'd 529 */ 530 if (attr->va_size == 0) 531 return (ENOEXEC); 532 533 /* 534 * Disable setuid/setgid if the filesystem prohibits it or if 535 * the process is being traced. 536 */ 537 if ((vnodep->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED)) 538 attr->va_mode &= ~(VSUID | VSGID); 539 540 /* 541 * Check for execute permission to file based on current credentials. 542 * Then call filesystem specific open routine (which does nothing 543 * in the general case). 544 */ 545 error = VOP_ACCESS(vnodep, VEXEC, p->p_ucred, p); 546 if (error) 547 return (error); 548 549 error = VOP_OPEN(vnodep, FREAD, p->p_ucred, p); 550 if (error) 551 return (error); 552 553 return (0); 554 } 555