diff options
author | marius eriksen <marius@cvs.openbsd.org> | 2004-07-07 07:31:41 +0000 |
---|---|---|
committer | marius eriksen <marius@cvs.openbsd.org> | 2004-07-07 07:31:41 +0000 |
commit | 84657162448d7dbd205d918f5037d931ee6a9727 (patch) | |
tree | 268cffd2d4e6cd224236d592a7cdc77c141b97d7 /sys | |
parent | a3d11b2a3cd27f4514d2ca0027d29e93924b6e37 (diff) |
fix an issue when scripts are exec'd under systrace where
the argv[0] would be normalized, and hence break scripts
that depend on how they were called.
this fixes an issue in the ports builds.
ok provos@ deraadt@; lots of testing during hackathon sturm@ naddy@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/systrace.c | 139 | ||||
-rw-r--r-- | sys/dev/systrace.h | 13 | ||||
-rw-r--r-- | sys/kern/exec_script.c | 20 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 7 |
4 files changed, 140 insertions, 39 deletions
diff --git a/sys/dev/systrace.c b/sys/dev/systrace.c index 0d19bf5bb23..6af4929574f 100644 --- a/sys/dev/systrace.c +++ b/sys/dev/systrace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.c,v 1.35 2004/06/23 05:16:35 marius Exp $ */ +/* $OpenBSD: systrace.c,v 1.36 2004/07/07 07:31:40 marius Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -118,6 +118,9 @@ struct str_process { gid_t setegid; gid_t savegid; + int isscript; + char scriptname[MAXPATHLEN]; + struct str_message msg; }; @@ -140,6 +143,8 @@ systrace_unlock(void) int systrace_attach(struct fsystrace *, pid_t); int systrace_detach(struct str_process *); int systrace_answer(struct str_process *, struct systrace_answer *); +int systrace_setscriptname(struct str_process *, + struct systrace_scriptname *); int systrace_io(struct str_process *, struct systrace_io *); int systrace_policy(struct fsystrace *, struct systrace_policy *); int systrace_preprepl(struct str_process *, struct systrace_replace *); @@ -283,6 +288,11 @@ systracef_ioctl(fp, cmd, data, p) if (!pid) ret = EINVAL; break; + case STRIOCSCRIPTNAME: + pid = ((struct systrace_scriptname *)data)->sn_pid; + if (!pid) + ret = EINVAL; + break; case STRIOCGETCWD: pid = *(pid_t *)data; if (!pid) @@ -337,6 +347,10 @@ systracef_ioctl(fp, cmd, data, p) case STRIOCIO: ret = systrace_io(strp, (struct systrace_io *)data); break; + case STRIOCSCRIPTNAME: + ret = systrace_setscriptname(strp, + (struct systrace_scriptname *)data); + break; case STRIOCPOLICY: ret = systrace_policy(fst, (struct systrace_policy *)data); break; @@ -959,6 +973,15 @@ systrace_answer(struct str_process *strp, struct systrace_answer *ans) } int +systrace_setscriptname(struct str_process *strp, struct systrace_scriptname *ans) +{ + strlcpy(strp->scriptname, + ans->sn_scriptname, sizeof(strp->scriptname)); + + return (0); +} + +int systrace_policy(struct fsystrace *fst, struct systrace_policy *pol) { struct str_policy *strpol; @@ -1192,37 +1215,49 @@ systrace_attach(struct fsystrace *fst, pid_t pid) } void -systrace_execve(char *path, struct proc *p) +systrace_execve0(struct proc *p) +{ + struct str_process *strp; + + systrace_lock(); + strp = p->p_systrace; + strp->isscript = 0; + systrace_unlock(); +} + +void +systrace_execve1(char *path, struct proc *p) { - struct str_process *strp; - struct fsystrace *fst; - struct str_msg_execve *msg_execve; - - do { - systrace_lock(); - strp = p->p_systrace; - if (strp == NULL) { - systrace_unlock(); - return; - } - - msg_execve = &strp->msg.msg_data.msg_execve; - fst = strp->parent; - lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p); - 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) { - lockmgr(&fst->lock, LK_RELEASE, NULL, p); - return; - } - strlcpy(msg_execve->path, path, MAXPATHLEN); - } while (systrace_make_msg(strp, SYSTR_MSG_EXECVE) != 0); + struct str_process *strp; + struct fsystrace *fst; + struct str_msg_execve *msg_execve; + + do { + systrace_lock(); + strp = p->p_systrace; + if (strp == NULL) { + systrace_unlock(); + return; + } + + msg_execve = &strp->msg.msg_data.msg_execve; + fst = strp->parent; + lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p); + 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) { + lockmgr(&fst->lock, LK_RELEASE, NULL, p); + return; + } + strlcpy(msg_execve->path, path, MAXPATHLEN); + } while (systrace_make_msg(strp, SYSTR_MSG_EXECVE) != 0); } /* Prepare to replace arguments */ @@ -1352,6 +1387,44 @@ systrace_replacefree(struct str_process *strp) strp->fname[strp->nfname] = NULL; } } +int +systrace_scriptname(struct proc *p, char *dst) +{ + struct str_process *strp; + struct fsystrace *fst; + int error = 0; + + systrace_lock(); + strp = p->p_systrace; + fst = strp->parent; + + lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p); + systrace_unlock(); + + if (!fst->issuser && (ISSET(p->p_flag, P_SUGID) || + ISSET(p->p_flag, P_SUGIDEXEC) || + fst->p_ruid != p->p_cred->p_ruid || + fst->p_rgid != p->p_cred->p_rgid)) { + error = EPERM; + goto out; + } + + if (strp != NULL) { + if (strp->scriptname[0] == '\0') { + error = ENOENT; + goto out; + } + + strlcpy(dst, strp->scriptname, MAXPATHLEN); + strp->isscript = 1; + } + + out: + strp->scriptname[0] = '\0'; + lockmgr(&fst->lock, LK_RELEASE, NULL, p); + + return (error); +} void systrace_namei(struct nameidata *ndp) @@ -1375,6 +1448,10 @@ systrace_namei(struct nameidata *ndp) break; } + if (!hamper && strp->isscript && + strcmp(cnp->cn_pnbuf, strp->scriptname) == 0) + hamper = 1; + lockmgr(&fst->lock, LK_RELEASE, NULL, curproc); } else systrace_unlock(); diff --git a/sys/dev/systrace.h b/sys/dev/systrace.h index e221ec32b13..3926cb9b2c0 100644 --- a/sys/dev/systrace.h +++ b/sys/dev/systrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.h,v 1.16 2004/06/23 05:16:35 marius Exp $ */ +/* $OpenBSD: systrace.h,v 1.17 2004/07/07 07:31:40 marius Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -74,6 +74,7 @@ struct str_msg_child { #define SYSTR_MSG_UGID 5 #define SYSTR_MSG_POLICYFREE 6 #define SYSTR_MSG_EXECVE 7 +#define SYSTR_MSG_SCRIPTNAME 8 #define SYSTR_MSG_NOPROCESS(x) \ ((x)->msg.msg_type == SYSTR_MSG_CHILD || \ @@ -104,6 +105,11 @@ struct systrace_answer { int stra_flags; }; +struct systrace_scriptname { + pid_t sn_pid; + char sn_scriptname[MAXPATHLEN]; +}; + #define SYSTR_READ 1 #define SYSTR_WRITE 2 @@ -163,6 +169,7 @@ struct systrace_replace { #define STRIOCRESCWD _IO('s', 107) #define STRIOCREPORT _IOW('s', 108, pid_t) #define STRIOCREPLACE _IOW('s', 109, struct systrace_replace) +#define STRIOCSCRIPTNAME _IOW('s', 110, struct systrace_scriptname) #define SYSTR_POLICY_ASK 0 #define SYSTR_POLICY_PERMIT 1 @@ -206,7 +213,9 @@ void systrace_namei(struct nameidata *); int systrace_redirect(int, struct proc *, void *, register_t *); void systrace_exit(struct proc *); void systrace_fork(struct proc *, struct proc *); -void systrace_execve(char *, struct proc *); +void systrace_execve0(struct proc *); +void systrace_execve1(char *, struct proc *); +int systrace_scriptname(struct proc *, char *); #endif /* _KERNEL */ #endif /* _SYSTRACE_H_ */ diff --git a/sys/kern/exec_script.c b/sys/kern/exec_script.c index e0af44c583d..ba6b99f0575 100644 --- a/sys/kern/exec_script.c +++ b/sys/kern/exec_script.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_script.c,v 1.20 2004/06/23 05:16:35 marius Exp $ */ +/* $OpenBSD: exec_script.c,v 1.21 2004/07/07 07:31:40 marius Exp $ */ /* $NetBSD: exec_script.c,v 1.13 1996/02/04 02:15:06 christos Exp $ */ /* @@ -221,11 +221,23 @@ check_shell: #endif /* normally can't fail, but check for it if diagnostic */ #if NSYSTRACE > 0 - error = copystr(epp->ep_name, *tmpsap++, MAXPATHLEN, - (size_t *)0); + error = 1; + if (ISSET(p->p_flag, P_SYSTRACE)) { + error = systrace_scriptname(p, *tmpsap); + if (error == 0) + tmpsap++; + } + if (error != 0) + /* + * Since systrace_scriptname() provides a + * convenience, not a security issue, we are + * safe to do this. + */ + error = copystr(epp->ep_name, *tmpsap++, + MAXPATHLEN, NULL); #else error = copyinstr(epp->ep_name, *tmpsap++, MAXPATHLEN, - (size_t *)0); + (size_t *)0); #endif #ifdef DIAGNOSTIC if (error != 0) diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index c7fb1aad5d3..cfb0ecc0bef 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exec.c,v 1.87 2004/06/23 05:16:35 marius Exp $ */ +/* $OpenBSD: kern_exec.c,v 1.88 2004/07/07 07:31:40 marius Exp $ */ /* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */ /*- @@ -275,6 +275,9 @@ sys_execve(p, v, retval) p->p_flag |= P_INEXEC; #if NSYSTRACE > 0 + if (ISSET(p->p_flag, P_SYSTRACE)) + systrace_execve0(p); + error = copyinstr(SCARG(uap, path), pathbuf, MAXPATHLEN, &pathbuflen); if (error != 0) goto clrflag; @@ -653,7 +656,7 @@ sys_execve(p, v, retval) if (ISSET(p->p_flag, P_SYSTRACE) && wassugid && !ISSET(p->p_flag, P_SUGID) && !ISSET(p->p_flag, P_SUGIDEXEC)) - systrace_execve(pathbuf, p); + systrace_execve1(pathbuf, p); #endif return (0); |