diff options
| author | elad <elad@NetBSD.org> | 2005-06-26 19:58:29 +0000 |
|---|---|---|
| committer | elad <elad@NetBSD.org> | 2005-06-26 19:58:29 +0000 |
| commit | 8ebc2e9beec6e592b40d97596776d080e2b3b63c (patch) | |
| tree | 0c442dbf5206a8f6ab380feb292791074a7400ed /sys | |
| parent | 5b718ea54c145b7e760d67177c40cc8d02dfe719 (diff) | |
From marius@openbsd:
Add an exec message so that whenever a set-uid/gid process executes a new
image which we may control, the exec does not go by unnoticed.
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/kern/exec_script.c | 13 | ||||
| -rw-r--r-- | sys/kern/kern_exec.c | 46 | ||||
| -rw-r--r-- | sys/kern/kern_systrace.c | 67 | ||||
| -rw-r--r-- | sys/sys/systrace.h | 9 |
4 files changed, 113 insertions, 22 deletions
diff --git a/sys/kern/exec_script.c b/sys/kern/exec_script.c index 4b2dc1bd161..36a93503dc7 100644 --- a/sys/kern/exec_script.c +++ b/sys/kern/exec_script.c @@ -1,4 +1,4 @@ -/* $NetBSD: exec_script.c,v 1.39 2005/05/19 20:16:19 elad Exp $ */ +/* $NetBSD: exec_script.c,v 1.40 2005/06/26 19:58:29 elad Exp $ */ /* * Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: exec_script.c,v 1.39 2005/05/19 20:16:19 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exec_script.c,v 1.40 2005/06/26 19:58:29 elad Exp $"); #if defined(SETUIDSCRIPTS) && !defined(FDSCRIPTS) #define FDSCRIPTS /* Need this for safe set-id scripts. */ @@ -56,6 +56,10 @@ __KERNEL_RCSID(0, "$NetBSD: exec_script.c,v 1.39 2005/05/19 20:16:19 elad Exp $" #include <sys/verified_exec.h> +#ifdef SYSTRACE +#include <sys/systrace.h> +#endif /* SYSTRACE */ + /* * exec_script_makecmds(): Check if it's an executable shell script. * @@ -225,8 +229,13 @@ check_shell: if ((epp->ep_flags & EXEC_HASFD) == 0) { #endif /* normally can't fail, but check for it if diagnostic */ +#ifdef SYSTRACE + error = copystr(epp->ep_name, *tmpsap++, MAXPATHLEN, + (size_t *)0); +#else error = copyinstr(epp->ep_name, *tmpsap++, MAXPATHLEN, (size_t *)0); +#endif /* SYSTRACE */ #ifdef DIAGNOSTIC if (error != 0) panic("exec_script: copyinstr couldn't fail"); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 33d0ca6eab1..65ac44c5184 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_exec.c,v 1.199 2005/06/10 23:32:16 elad Exp $ */ +/* $NetBSD: kern_exec.c,v 1.200 2005/06/26 19:58:29 elad Exp $ */ /*- * Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou @@ -33,7 +33,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.199 2005/06/10 23:32:16 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.200 2005/06/26 19:58:29 elad Exp $"); #include "opt_ktrace.h" #include "opt_syscall_debug.h" @@ -67,6 +67,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.199 2005/06/10 23:32:16 elad Exp $") #include <sys/verified_exec.h> #endif +#ifdef SYSTRACE +#include <sys/systrace.h> +#endif /* SYSTRACE */ + #include <uvm/uvm_extern.h> #include <machine/cpu.h> @@ -201,7 +205,7 @@ static void link_es(struct execsw_entry **, const struct execsw *); * ON ENTRY: * exec package with appropriate namei info * proc pointer of exec'ing proc - * iff verified exec enabled then flag indicating a direct exec or + * if verified exec enabled then flag indicating a direct exec or * an indirect exec (i.e. for a shell script interpreter) * NO SELF-LOCKED VNODES * @@ -222,7 +226,7 @@ static void link_es(struct execsw_entry **, const struct execsw *); */ int #ifdef VERIFIED_EXEC -check_exec(struct proc *p, struct exec_package *epp, int direct_exec) +check_exec(struct proc *p, struct exec_package *epp, int flag) #else check_exec(struct proc *p, struct exec_package *epp) #endif @@ -270,8 +274,8 @@ check_exec(struct proc *p, struct exec_package *epp) #ifdef VERIFIED_EXEC /* Evaluate signature for file... */ - if ((error = veriexec_verify(p, vp, epp->ep_vap, - epp->ep_name, direct_exec)) != 0) + if ((error = veriexec_verify(p, vp, epp->ep_vap, epp->ep_name, + flag, NULL)) != 0) goto bad2; #endif @@ -391,6 +395,11 @@ sys_execve(struct lwp *l, void *v, register_t *retval) int szsigcode; struct exec_vmcmd *base_vcp; int oldlwpflags; +#ifdef SYSTRACE + int wassugid = ISSET(p->p_flag, P_SUGID); + char pathbuf[MAXPATHLEN]; + size_t pathbuflen; +#endif /* SYSTRACE */ /* Disable scheduler activation upcalls. */ oldlwpflags = l->l_flag & (L_SA | L_SA_UPCALL); @@ -416,12 +425,25 @@ sys_execve(struct lwp *l, void *v, register_t *retval) * functions call check_exec() recursively - for example, * see exec_script_makecmds(). */ +#ifdef SYSTRACE + error = copyinstr(SCARG(uap, path), pathbuf, sizeof(pathbuf), + &pathbuflen); + if (error) + goto clrflg; + + NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p); +#else NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); +#endif /* SYSTRACE */ /* * initialize the fields of the exec package. */ +#ifdef SYSTRACE + pack.ep_name = pathbuf; +#else pack.ep_name = SCARG(uap, path); +#endif /* SYSTRACE */ pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK); pack.ep_hdrlen = exec_maxhdrsz; pack.ep_hdrvalid = 0; @@ -843,6 +865,12 @@ sys_execve(struct lwp *l, void *v, register_t *retval) splx(s); } +#ifdef SYSTRACE + if (ISSET(p->p_flag, P_SYSTRACE) && + wassugid && !ISSET(p->p_flag, P_SUGID)) + systrace_execve(pathbuf, p); +#endif /* SYSTRACE */ + return (EJUSTRETURN); bad: @@ -862,13 +890,17 @@ sys_execve(struct lwp *l, void *v, register_t *retval) uvm_km_free(exec_map, (vaddr_t) argp, NCARGS, UVM_KMF_PAGEABLE); freehdr: + free(pack.ep_hdr, M_EXEC); + +#ifdef SYSTRACE + clrflg: +#endif /* SYSTRACE */ l->l_flag |= oldlwpflags; p->p_flag &= ~P_INEXEC; #ifdef LKM lockmgr(&exec_lock, LK_RELEASE, NULL); #endif - free(pack.ep_hdr, M_EXEC); return error; exec_abort: diff --git a/sys/kern/kern_systrace.c b/sys/kern/kern_systrace.c index 5d44fc0c828..989cb5a33f3 100644 --- a/sys/kern/kern_systrace.c +++ b/sys/kern/kern_systrace.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_systrace.c,v 1.44 2005/02/26 21:34:55 perry Exp $ */ +/* $NetBSD: kern_systrace.c,v 1.45 2005/06/26 19:58:29 elad Exp $ */ /* * Copyright 2002, 2003 Niels Provos <provos@citi.umich.edu> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_systrace.c,v 1.44 2005/02/26 21:34:55 perry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_systrace.c,v 1.45 2005/06/26 19:58:29 elad Exp $"); #include "opt_systrace.h" @@ -1242,6 +1242,42 @@ systrace_attach(struct fsystrace *fst, pid_t pid) return (error); } +void +systrace_execve(char *path, struct proc *p) +{ + struct str_process *strp; + struct fsystrace *fst; + struct str_message msg; + struct str_msg_execve *msg_execve; + + do { + systrace_lock(); + strp = p->p_systrace; + if (strp == NULL) { + systrace_unlock(); + return; + } + + msg_execve = &msg.msg_data.msg_execve; + fst = strp->parent; + SYSTRACE_LOCK(fst, curlwp); + systrace_unlock(); + + /* + * susers will get the execve call anyway. Also, if + * we're not allowed to control the process, escape. + */ + if (fst->issuser || + fst->p_ruid != p->p_cred->p_ruid || + fst->p_rgid != p->p_cred->p_rgid) { + SYSTRACE_UNLOCK(fst, curlwp); + return; + } + + strlcpy(msg_execve->path, path, sizeof(msg_execve->path)); + } while (systrace_make_msg(strp, SYSTR_MSG_EXECVE, &msg) != 0); +} + /* Prepare to replace arguments */ int @@ -1348,7 +1384,6 @@ systrace_replace(struct str_process *strp, size_t argsize, register_t args[]) int systrace_fname(struct str_process *strp, caddr_t kdata, size_t len) { - if (strp->nfname >= SYSTR_MAXFNAME || len < 2) return EINVAL; @@ -1377,9 +1412,10 @@ void systrace_namei(struct nameidata *ndp) { struct str_process *strp; - struct fsystrace *fst; + struct fsystrace *fst = NULL; /* XXXGCC */ struct componentname *cnp = &ndp->ni_cnd; size_t i; + int hamper = 0; systrace_lock(); strp = cnp->cn_proc->p_systrace; @@ -1388,18 +1424,21 @@ systrace_namei(struct nameidata *ndp) SYSTRACE_LOCK(fst, curlwp); systrace_unlock(); - for (i = 0; i < strp->nfname; i++) { + for (i = 0; i < strp->nfname; i++) if (strcmp(cnp->cn_pnbuf, strp->fname[i]) == 0) { - /* ELOOP if namei() tries to readlink */ - ndp->ni_loopcnt = MAXSYMLINKS; - cnp->cn_flags &= ~FOLLOW; - cnp->cn_flags |= NOFOLLOW; + hamper = 1; break; } - } SYSTRACE_UNLOCK(fst, curlwp); } else systrace_unlock(); + + if (hamper) { + /* ELOOP if namei() tries to readlink */ + ndp->ni_loopcnt = MAXSYMLINKS; + cnp->cn_flags &= ~FOLLOW; + cnp->cn_flags |= NOFOLLOW; + } } struct str_process * @@ -1614,7 +1653,11 @@ systrace_make_msg(struct str_process *strp, int type, struct str_message *tmsg) struct str_msgcontainer *cont; struct str_message *msg; struct fsystrace *fst = strp->parent; - int st; + int st, pri; + + pri = PWAIT|PCATCH; + if (type == SYSTR_MSG_EXECVE) + pri &= ~PCATCH; cont = pool_get(&systr_msgcontainer_pl, PR_WAITOK); memset(cont, 0, sizeof(struct str_msgcontainer)); @@ -1651,7 +1694,7 @@ systrace_make_msg(struct str_process *strp, int type, struct str_message *tmsg) int f; f = curlwp->l_flag & L_SA; curlwp->l_flag &= ~L_SA; - st = tsleep(strp, PWAIT | PCATCH, "systrmsg", 0); + st = tsleep(strp, pri, "systrmsg", 0); curlwp->l_flag |= f; if (st != 0) return (ERESTART); diff --git a/sys/sys/systrace.h b/sys/sys/systrace.h index 2e0857834d4..71f85fae272 100644 --- a/sys/sys/systrace.h +++ b/sys/sys/systrace.h @@ -1,4 +1,4 @@ -/* $NetBSD: systrace.h,v 1.12 2003/10/31 03:28:14 simonb Exp $ */ +/* $NetBSD: systrace.h,v 1.13 2005/06/26 19:58:29 elad Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> @@ -48,6 +48,10 @@ struct str_msg_ugid { gid_t gid; }; +struct str_msg_execve { + char path[MAXPATHLEN]; +}; + #define SYSTR_MAX_POLICIES 64 #define SYSTR_MAXARGS 64 #define SYSTR_MAXFNAME 8 @@ -72,6 +76,7 @@ struct str_msg_child { #define SYSTR_MSG_CHILD 4 #define SYSTR_MSG_UGID 5 #define SYSTR_MSG_POLICYFREE 6 +#define SYSTR_MSG_EXECVE 7 #define SYSTR_MSG_NOPROCESS(x) \ ((x)->msg.msg_type == SYSTR_MSG_CHILD || \ @@ -87,6 +92,7 @@ struct str_message { struct str_msg_ugid msg_ugid; struct str_msg_ask msg_ask; struct str_msg_child msg_child; + struct str_msg_execve msg_execve; } msg_data; }; @@ -216,6 +222,7 @@ void systrace_exit(struct proc *, register_t, void *, register_t [], int); void systrace_sys_exit(struct proc *); void systrace_sys_fork(struct proc *, struct proc *); void systrace_init(void); +void systrace_execve(char *, struct proc *); #endif /* _KERNEL */ #endif /* !_SYSTRACE_H_ */ |
