summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authormarius eriksen <marius@cvs.openbsd.org>2004-07-07 07:31:41 +0000
committermarius eriksen <marius@cvs.openbsd.org>2004-07-07 07:31:41 +0000
commit84657162448d7dbd205d918f5037d931ee6a9727 (patch)
tree268cffd2d4e6cd224236d592a7cdc77c141b97d7 /sys
parenta3d11b2a3cd27f4514d2ca0027d29e93924b6e37 (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.c139
-rw-r--r--sys/dev/systrace.h13
-rw-r--r--sys/kern/exec_script.c20
-rw-r--r--sys/kern/kern_exec.c7
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);