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 | |
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@
-rw-r--r-- | bin/systrace/intercept-translate.c | 8 | ||||
-rw-r--r-- | bin/systrace/intercept.c | 15 | ||||
-rw-r--r-- | bin/systrace/intercept.h | 5 | ||||
-rw-r--r-- | bin/systrace/openbsd-syscalls.c | 15 | ||||
-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 |
8 files changed, 172 insertions, 50 deletions
diff --git a/bin/systrace/intercept-translate.c b/bin/systrace/intercept-translate.c index 41d385bfa3a..4c6d7cea22e 100644 --- a/bin/systrace/intercept-translate.c +++ b/bin/systrace/intercept-translate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intercept-translate.c,v 1.10 2003/10/08 16:32:44 sturm Exp $ */ +/* $OpenBSD: intercept-translate.c,v 1.11 2004/07/07 07:31:40 marius Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -133,7 +133,7 @@ ic_get_filename(struct intercept_translate *trans, int fd, pid_t pid, char *name; int len; - name = intercept_filename(fd, pid, addr, ICLINK_ALL); + name = intercept_filename(fd, pid, addr, ICLINK_ALL, NULL); if (name == NULL) return (-1); @@ -180,7 +180,7 @@ ic_get_linkname(struct intercept_translate *trans, int fd, pid_t pid, char *name; int len; - name = intercept_filename(fd, pid, addr, ICLINK_NONE); + name = intercept_filename(fd, pid, addr, ICLINK_NONE, NULL); if (name == NULL) return (-1); @@ -204,7 +204,7 @@ ic_get_unlinkname(struct intercept_translate *trans, int fd, pid_t pid, char *name; int len; - name = intercept_filename(fd, pid, addr, ICLINK_NOLAST); + name = intercept_filename(fd, pid, addr, ICLINK_NOLAST, NULL); if (name == NULL) return (-1); diff --git a/bin/systrace/intercept.c b/bin/systrace/intercept.c index b79faf2755e..61f72435f0b 100644 --- a/bin/systrace/intercept.c +++ b/bin/systrace/intercept.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intercept.c,v 1.48 2004/06/24 21:00:10 marius Exp $ */ +/* $OpenBSD: intercept.c,v 1.49 2004/07/07 07:31:40 marius Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -585,13 +585,16 @@ intercept_get_string(int fd, pid_t pid, void *addr) } char * -intercept_filename(int fd, pid_t pid, void *addr, int userp) +intercept_filename(int fd, pid_t pid, void *addr, int userp, char *before) { char *name; if ((name = intercept_get_string(fd, pid, addr)) == NULL) goto abort; + if (before != NULL) + strlcpy(before, name, MAXPATHLEN); + if ((name = normalize_filename(fd, pid, name, userp)) == NULL) goto abort; @@ -746,7 +749,7 @@ intercept_syscall(int fd, pid_t pid, u_int16_t seqnr, int policynr, /* Special handling for the exec call */ if (!strcmp(name, "execve")) { void *addr; - char *argname; + char *argname, before[MAXPATHLEN]; icpid->execve_code = code; icpid->policynr = policynr; @@ -755,10 +758,14 @@ intercept_syscall(int fd, pid_t pid, u_int16_t seqnr, int policynr, free(icpid->newname); intercept.getarg(0, args, argsize, &addr); - argname = intercept_filename(fd, pid, addr, ICLINK_ALL); + argname = intercept_filename(fd, pid, addr, ICLINK_ALL, before); if (argname == NULL) err(1, "%s:%d: intercept_filename", __func__, __LINE__); + + if (intercept.scriptname(fd, pid, before) != 0) + err(1, "%s:%d: ioctl", __func__, __LINE__); + icpid->newname = strdup(argname); if (icpid->newname == NULL) err(1, "%s:%d: strdup", __func__, __LINE__); diff --git a/bin/systrace/intercept.h b/bin/systrace/intercept.h index 9bb9da7ecdd..a470cf20f5b 100644 --- a/bin/systrace/intercept.h +++ b/bin/systrace/intercept.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intercept.h,v 1.20 2004/06/23 05:16:35 marius Exp $ */ +/* $OpenBSD: intercept.h,v 1.21 2004/07/07 07:31:40 marius Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -59,6 +59,7 @@ struct intercept_system { int (*replace)(int, pid_t, u_int16_t, struct intercept_replace *); void (*clonepid)(struct intercept_pid *, struct intercept_pid *); void (*freepid)(struct intercept_pid *); + int (*scriptname)(int, pid_t, char *); }; #define INTERCEPT_READ 1 @@ -189,7 +190,7 @@ int intercept_existpids(void); char *intercept_get_string(int, pid_t, void *); char *normalize_filename(int, pid_t, char *, int); -char *intercept_filename(int, pid_t, void *, int); +char *intercept_filename(int, pid_t, void *, int, char *); void intercept_syscall(int, pid_t, u_int16_t, int, const char *, int, const char *, void *, int); void intercept_syscall_result(int, pid_t, u_int16_t, int, const char *, int, diff --git a/bin/systrace/openbsd-syscalls.c b/bin/systrace/openbsd-syscalls.c index d806b0784ce..4f45909a3c3 100644 --- a/bin/systrace/openbsd-syscalls.c +++ b/bin/systrace/openbsd-syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: openbsd-syscalls.c,v 1.24 2004/06/23 05:16:35 marius Exp $ */ +/* $OpenBSD: openbsd-syscalls.c,v 1.25 2004/07/07 07:31:40 marius Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -139,6 +139,7 @@ static int obsd_setcwd(int, pid_t); static int obsd_restcwd(int); static int obsd_argument(int, void *, int, void **); static int obsd_read(int); +static int obsd_scriptname(int, pid_t, char *); static int obsd_init(void) @@ -382,6 +383,17 @@ obsd_answer(int fd, pid_t pid, u_int32_t seqnr, short policy, int nerrno, return (0); } +static int +obsd_scriptname(int fd, pid_t pid, char *scriptname) +{ + struct systrace_scriptname sn; + + sn.sn_pid = pid; + strlcpy(sn.sn_scriptname, scriptname, sizeof(sn.sn_scriptname)); + + return (ioctl(fd, STRIOCSCRIPTNAME, &sn)); +} + static int obsd_newpolicy(int fd) { @@ -663,4 +675,5 @@ struct intercept_system intercept = { obsd_replace, obsd_clonepid, obsd_freepid, + obsd_scriptname, }; 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); |