summaryrefslogtreecommitdiff
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
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@
-rw-r--r--bin/systrace/intercept-translate.c8
-rw-r--r--bin/systrace/intercept.c15
-rw-r--r--bin/systrace/intercept.h5
-rw-r--r--bin/systrace/openbsd-syscalls.c15
-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
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);