xref: /freebsd/sys/kern/kern_exec.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
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.19 1995/03/25 01:20:38 davidg Exp $
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/signalvar.h>
37 #include <sys/kernel.h>
38 #include <sys/mount.h>
39 #include <sys/filedesc.h>
40 #include <sys/file.h>
41 #include <sys/acct.h>
42 #include <sys/exec.h>
43 #include <sys/imgact.h>
44 #include <sys/wait.h>
45 #include <sys/malloc.h>
46 #include <sys/sysent.h>
47 #include <sys/syslog.h>
48 #include <sys/shm.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 const struct execsw **execsw = (const struct execsw **)&execsw_set.ls_items[0];
64 
65 /*
66  * execve() system call.
67  */
68 int
69 execve(p, uap, retval)
70 	struct proc *p;
71 	register struct execve_args *uap;
72 	int *retval;
73 {
74 	struct nameidata nd, *ndp;
75 	int *stack_base;
76 	int error, len, i;
77 	struct image_params image_params, *iparams;
78 	struct vnode *vnodep;
79 	struct vattr attr;
80 	char *image_header;
81 
82 	iparams = &image_params;
83 	bzero((caddr_t)iparams, sizeof(struct image_params));
84 	image_header = (char *)0;
85 
86 	/*
87 	 * Initialize a few constants in the common area
88 	 */
89 	iparams->proc = p;
90 	iparams->uap = uap;
91 	iparams->attr = &attr;
92 
93 	/*
94 	 * Allocate temporary demand zeroed space for argument and
95 	 *	environment strings
96 	 */
97 	iparams->stringbase = (char *)vm_map_min(exec_map);
98 	error = vm_map_find(exec_map, NULL, 0, (vm_offset_t *)&iparams->stringbase,
99 	    ARG_MAX, TRUE);
100 	if (error) {
101 		log(LOG_WARNING, "execve: failed to allocate string space\n");
102 		return (error);
103 	}
104 
105 	if (!iparams->stringbase) {
106 		error = ENOMEM;
107 		goto exec_fail;
108 	}
109 	iparams->stringp = iparams->stringbase;
110 	iparams->stringspace = ARG_MAX;
111 
112 	/*
113 	 * Translate the file name. namei() returns a vnode pointer
114 	 *	in ni_vp amoung other things.
115 	 */
116 	ndp = &nd;
117 	NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
118 	    UIO_USERSPACE, uap->fname, p);
119 
120 interpret:
121 
122 	error = namei(ndp);
123 	if (error) {
124 		vm_map_remove(exec_map, (vm_offset_t)iparams->stringbase,
125 		    (vm_offset_t)iparams->stringbase + ARG_MAX);
126 		goto exec_fail;
127 	}
128 
129 	iparams->vnodep = vnodep = ndp->ni_vp;
130 
131 	if (vnodep == NULL) {
132 		error = ENOEXEC;
133 		goto exec_fail_dealloc;
134 	}
135 
136 	/*
137 	 * Check file permissions (also 'opens' file)
138 	 */
139 	error = exec_check_permissions(iparams);
140 
141 	/*
142 	 * Lose the lock on the vnode. It's no longer needed, and must not
143 	 * exist for the pagefault paging to work below.
144 	 */
145 	VOP_UNLOCK(vnodep);
146 
147 	if (error)
148 		goto exec_fail_dealloc;
149 
150 	/*
151 	 * Map the image header (first page) of the file into
152 	 *	kernel address space
153 	 */
154 	error = vm_mmap(kernel_map,			/* map */
155 			(vm_offset_t *)&image_header,	/* address */
156 			PAGE_SIZE,			/* size */
157 			VM_PROT_READ, 			/* protection */
158 			VM_PROT_READ, 			/* max protection */
159 			0,	 			/* flags */
160 			(caddr_t)vnodep,		/* vnode */
161 			0);				/* offset */
162 	if (error) {
163 		uprintf("mmap failed: %d\n",error);
164 		goto exec_fail_dealloc;
165 	}
166 	iparams->image_header = image_header;
167 
168 	/*
169 	 * Loop through list of image activators, calling each one.
170 	 *	If there is no match, the activator returns -1. If there
171 	 *	is a match, but there was an error during the activation,
172 	 *	the error is returned. Otherwise 0 means success. If the
173 	 *	image is interpreted, loop back up and try activating
174 	 *	the interpreter.
175 	 */
176 	for (i = 0; execsw[i]; ++i) {
177 		if (execsw[i]->ex_imgact)
178 			error = (*execsw[i]->ex_imgact)(iparams);
179 		else
180 			continue;
181 
182 		if (error == -1)
183 			continue;
184 		if (error)
185 			goto exec_fail_dealloc;
186 		if (iparams->interpreted) {
187 			/* free old vnode and name buffer */
188 			vrele(ndp->ni_vp);
189 			FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI);
190 			if (vm_map_remove(kernel_map, (vm_offset_t)image_header,
191 			    (vm_offset_t)image_header + PAGE_SIZE))
192 				panic("execve: header dealloc failed (1)");
193 
194 			/* set new name to that of the interpreter */
195 			NDINIT(ndp, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME,
196 			    UIO_SYSSPACE, iparams->interpreter_name, p);
197 			goto interpret;
198 		}
199 		break;
200 	}
201 	/* If we made it through all the activators and none matched, exit. */
202 	if (error == -1) {
203 		error = ENOEXEC;
204 		goto exec_fail_dealloc;
205 	}
206 
207 	/*
208 	 * Copy out strings (args and env) and initialize stack base
209 	 */
210 	stack_base = exec_copyout_strings(iparams);
211 	p->p_vmspace->vm_minsaddr = (char *)stack_base;
212 
213 	/*
214 	 * If custom stack fixup routine present for this process
215 	 * let it do the stack setup.
216 	 * Else stuff argument count as first item on stack
217 	 */
218 	if (p->p_sysent->sv_fixup)
219 		(*p->p_sysent->sv_fixup)(&stack_base, iparams);
220 	else
221 		suword(--stack_base, iparams->argc);
222 
223 	/* close files on exec */
224 	fdcloseexec(p);
225 
226 	/* reset caught signals */
227 	execsigs(p);
228 
229 	/* name this process - nameiexec(p, ndp) */
230 	len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN);
231 	bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len);
232 	p->p_comm[len] = 0;
233 
234 	/*
235 	 * mark as executable, wakeup any process that was vforked and tell
236 	 * it that it now has it's own resources back
237 	 */
238 	p->p_flag |= P_EXEC;
239 	if (p->p_pptr && (p->p_flag & P_PPWAIT)) {
240 		p->p_flag &= ~P_PPWAIT;
241 		wakeup((caddr_t)p->p_pptr);
242 	}
243 
244 	/* implement set userid/groupid */
245 	p->p_flag &= ~P_SUGID;
246 
247 	/*
248 	 * Turn off kernel tracing for set-id programs, except for
249 	 * root.
250 	 */
251 	if (p->p_tracep && (attr.va_mode & (VSUID | VSGID)) &&
252 	    suser(p->p_ucred, &p->p_acflag)) {
253 		p->p_traceflag = 0;
254 		vrele(p->p_tracep);
255 		p->p_tracep = 0;
256 	}
257 	if ((attr.va_mode & VSUID) && (p->p_flag & P_TRACED) == 0) {
258 		p->p_ucred = crcopy(p->p_ucred);
259 		p->p_ucred->cr_uid = attr.va_uid;
260 		p->p_flag |= P_SUGID;
261 	}
262 	if ((attr.va_mode & VSGID) && (p->p_flag & P_TRACED) == 0) {
263 		p->p_ucred = crcopy(p->p_ucred);
264 		p->p_ucred->cr_groups[0] = attr.va_gid;
265 		p->p_flag |= P_SUGID;
266 	}
267 
268 	/*
269 	 * Implement correct POSIX saved uid behavior.
270 	 */
271 	p->p_cred->p_svuid = p->p_ucred->cr_uid;
272 	p->p_cred->p_svgid = p->p_ucred->cr_gid;
273 
274 	/* mark vnode pure text */
275  	ndp->ni_vp->v_flag |= VTEXT;
276 
277 	/*
278 	 * Store the vp for use in procfs
279 	 */
280 	if (p->p_textvp)		/* release old reference */
281 		vrele(p->p_textvp);
282 	VREF(ndp->ni_vp);
283 	p->p_textvp = ndp->ni_vp;
284 
285 	/*
286 	 * If tracing the process, trap to debugger so breakpoints
287 	 * 	can be set before the program executes.
288 	 */
289 	if (p->p_flag & P_TRACED)
290 		psignal(p, SIGTRAP);
291 
292 	/* clear "fork but no exec" flag, as we _are_ execing */
293 	p->p_acflag &= ~AFORK;
294 
295 	/* Set entry address */
296 	setregs(p, iparams->entry_addr, (u_long)stack_base);
297 
298 	/*
299 	 * free various allocated resources
300 	 */
301 	if (vm_map_remove(exec_map, (vm_offset_t)iparams->stringbase,
302 	    (vm_offset_t)iparams->stringbase + ARG_MAX))
303 		panic("execve: string buffer dealloc failed (1)");
304 	if (vm_map_remove(kernel_map, (vm_offset_t)image_header,
305 	    (vm_offset_t)image_header + PAGE_SIZE))
306 		panic("execve: header dealloc failed (2)");
307 	vrele(ndp->ni_vp);
308 	FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI);
309 
310 	return (0);
311 
312 exec_fail_dealloc:
313 	if (iparams->stringbase && iparams->stringbase != (char *)-1)
314 		if (vm_map_remove(exec_map, (vm_offset_t)iparams->stringbase,
315 		    (vm_offset_t)iparams->stringbase + ARG_MAX))
316 			panic("execve: string buffer dealloc failed (2)");
317 	if (iparams->image_header && iparams->image_header != (char *)-1)
318 		if (vm_map_remove(kernel_map, (vm_offset_t)image_header,
319 		    (vm_offset_t)image_header + PAGE_SIZE))
320 			panic("execve: header dealloc failed (3)");
321 	if (ndp->ni_vp)
322 		vrele(ndp->ni_vp);
323 	FREE(ndp->ni_cnd.cn_pnbuf, M_NAMEI);
324 
325 exec_fail:
326 	if (iparams->vmspace_destroyed) {
327 		/* sorry, no more process anymore. exit gracefully */
328 		exit1(p, W_EXITCODE(0, SIGABRT));
329 		/* NOT REACHED */
330 		return(0);
331 	} else {
332 		return(error);
333 	}
334 }
335 
336 /*
337  * Destroy old address space, and allocate a new stack
338  *	The new stack is only SGROWSIZ large because it is grown
339  *	automatically in trap.c.
340  */
341 int
342 exec_new_vmspace(iparams)
343 	struct image_params *iparams;
344 {
345 	int error;
346 	struct vmspace *vmspace = iparams->proc->p_vmspace;
347 	caddr_t	stack_addr = (caddr_t) (USRSTACK - SGROWSIZ);
348 
349 	iparams->vmspace_destroyed = 1;
350 
351 	/* Blow away entire process VM */
352 #ifdef SYSVSHM
353 	if (vmspace->vm_shm)
354 		shmexit(iparams->proc);
355 #endif
356 	vm_map_remove(&vmspace->vm_map, 0, USRSTACK);
357 
358 	/* Allocate a new stack */
359 	error = vm_map_find(&vmspace->vm_map, NULL, 0, (vm_offset_t *)&stack_addr,
360 	    SGROWSIZ, FALSE);
361 	if (error)
362 		return(error);
363 
364 	vmspace->vm_ssize = SGROWSIZ >> PAGE_SHIFT;
365 
366 	/* Initialize maximum stack address */
367 	vmspace->vm_maxsaddr = (char *)USRSTACK - MAXSSIZ;
368 
369 	return(0);
370 }
371 
372 /*
373  * Copy out argument and environment strings from the old process
374  *	address space into the temporary string buffer.
375  */
376 int
377 exec_extract_strings(iparams)
378 	struct image_params *iparams;
379 {
380 	char	**argv, **envv;
381 	char	*argp, *envp;
382 	int	error, length;
383 
384 	/*
385 	 * extract arguments first
386 	 */
387 
388 	argv = iparams->uap->argv;
389 
390 	if (argv) {
391 		while ((argp = (caddr_t) fuword(argv++))) {
392 			if (argp == (caddr_t) -1)
393 				return (EFAULT);
394 			if ((error = copyinstr(argp, iparams->stringp,
395 			    iparams->stringspace, &length))) {
396 				if (error == ENAMETOOLONG)
397 					return(E2BIG);
398 				return (error);
399 			}
400 			iparams->stringspace -= length;
401 			iparams->stringp += length;
402 			iparams->argc++;
403 		}
404 	}
405 
406 	/*
407 	 * extract environment strings
408 	 */
409 
410 	envv = iparams->uap->envv;
411 
412 	if (envv) {
413 		while ((envp = (caddr_t) fuword(envv++))) {
414 			if (envp == (caddr_t) -1)
415 				return (EFAULT);
416 			if ((error = copyinstr(envp, iparams->stringp,
417 			    iparams->stringspace, &length))) {
418 				if (error == ENAMETOOLONG)
419 					return(E2BIG);
420 				return (error);
421 			}
422 			iparams->stringspace -= length;
423 			iparams->stringp += length;
424 			iparams->envc++;
425 		}
426 	}
427 
428 	return (0);
429 }
430 
431 /*
432  * Copy strings out to the new process address space, constructing
433  *	new arg and env vector tables. Return a pointer to the base
434  *	so that it can be used as the initial stack pointer.
435  */
436 int *
437 exec_copyout_strings(iparams)
438 	struct image_params *iparams;
439 {
440 	int argc, envc;
441 	char **vectp;
442 	char *stringp, *destp;
443 	int *stack_base;
444 	struct ps_strings *arginfo;
445 
446 	/*
447 	 * Calculate string base and vector table pointers.
448 	 */
449 	arginfo = PS_STRINGS;
450 	destp =	(caddr_t)arginfo - roundup((ARG_MAX - iparams->stringspace), sizeof(char *));
451 	/*
452 	 * The '+ 2' is for the null pointers at the end of each of the
453 	 *	arg and	env vector sets
454 	 */
455 	vectp = (char **) (destp -
456 		(iparams->argc + iparams->envc + 2) * sizeof(char *));
457 
458 	/*
459 	 * vectp also becomes our initial stack base
460 	 */
461 	stack_base = (int *)vectp;
462 
463 	stringp = iparams->stringbase;
464 	argc = iparams->argc;
465 	envc = iparams->envc;
466 
467 	/*
468 	 * Copy out strings - arguments and environment.
469 	 */
470 	copyout(stringp, destp, ARG_MAX - iparams->stringspace);
471 
472 	/*
473 	 * Fill in "ps_strings" struct for ps, w, etc.
474 	 */
475 	suword(&arginfo->ps_argvstr, (int)destp);
476 	suword(&arginfo->ps_nargvstr, argc);
477 
478 	/*
479 	 * Fill in argument portion of vector table.
480 	 */
481 	for (; argc > 0; --argc) {
482 		suword(vectp++, (int)destp);
483 		while (*stringp++ != 0)
484 			destp++;
485 		destp++;
486 	}
487 
488 	/* a null vector table pointer seperates the argp's from the envp's */
489 	suword(vectp++, NULL);
490 
491 	suword(&arginfo->ps_envstr, (int)destp);
492 	suword(&arginfo->ps_nenvstr, envc);
493 
494 	/*
495 	 * Fill in environment portion of vector table.
496 	 */
497 	for (; envc > 0; --envc) {
498 		suword(vectp++, (int)destp);
499 		while (*stringp++ != 0)
500 			destp++;
501 		destp++;
502 	}
503 
504 	/* end of vector table is a null pointer */
505 	suword(vectp, NULL);
506 
507 	return (stack_base);
508 }
509 
510 /*
511  * Check permissions of file to execute.
512  *	Return 0 for success or error code on failure.
513  */
514 static int
515 exec_check_permissions(iparams)
516 	struct image_params *iparams;
517 {
518 	struct proc *p = iparams->proc;
519 	struct vnode *vnodep = iparams->vnodep;
520 	struct vattr *attr = iparams->attr;
521 	int error;
522 
523 	/*
524 	 * Check number of open-for-writes on the file and deny execution
525 	 *	if there are any.
526 	 */
527 	if (vnodep->v_writecount) {
528 		return (ETXTBSY);
529 	}
530 
531 	/* Get file attributes */
532 	error = VOP_GETATTR(vnodep, attr, p->p_ucred, p);
533 	if (error)
534 		return (error);
535 
536 	/*
537 	 * 1) Check if file execution is disabled for the filesystem that this
538 	 *	file resides on.
539 	 * 2) Insure that at least one execute bit is on - otherwise root
540 	 *	will always succeed, and we don't want to happen unless the
541 	 *	file really is executable.
542 	 * 3) Insure that the file is a regular file.
543 	 */
544 	if ((vnodep->v_mount->mnt_flag & MNT_NOEXEC) ||
545 	    ((attr->va_mode & 0111) == 0) ||
546 	    (attr->va_type != VREG)) {
547 		return (EACCES);
548 	}
549 
550 	/*
551 	 * Zero length files can't be exec'd
552 	 */
553 	if (attr->va_size == 0)
554 		return (ENOEXEC);
555 
556 	/*
557 	 * Disable setuid/setgid if the filesystem prohibits it or if
558 	 *	the process is being traced.
559 	 */
560         if ((vnodep->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED))
561 		attr->va_mode &= ~(VSUID | VSGID);
562 
563 	/*
564 	 *  Check for execute permission to file based on current credentials.
565 	 *	Then call filesystem specific open routine (which does nothing
566 	 *	in the general case).
567 	 */
568 	error = VOP_ACCESS(vnodep, VEXEC, p->p_ucred, p);
569 	if (error)
570 		return (error);
571 
572 	error = VOP_OPEN(vnodep, FREAD, p->p_ucred, p);
573 	if (error)
574 		return (error);
575 
576 	return (0);
577 }
578