summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2002-06-21 15:26:07 +0000
committerNiels Provos <provos@cvs.openbsd.org>2002-06-21 15:26:07 +0000
commiteab57a6ade26fd4b5b7c5642326ec2de9c01f56d (patch)
tree855c6a054cf99b284c5c766f6f6ce524208a106c
parentab636641a14766506bddd6c38591baa9f6c9b4ac (diff)
rewrite all system call arguments in the permit case. use realpath
when we still have the root and we of the monitored process. this eliminates almost all race coniditions.
-rw-r--r--bin/systrace/intercept-translate.c18
-rw-r--r--bin/systrace/intercept.c62
-rw-r--r--bin/systrace/intercept.h18
-rw-r--r--bin/systrace/openbsd-syscalls.c56
-rw-r--r--bin/systrace/systrace.c26
5 files changed, 148 insertions, 32 deletions
diff --git a/bin/systrace/intercept-translate.c b/bin/systrace/intercept-translate.c
index 7208156f9f2..d582ab3bfa0 100644
--- a/bin/systrace/intercept-translate.c
+++ b/bin/systrace/intercept-translate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept-translate.c,v 1.3 2002/06/19 16:31:07 provos Exp $ */
+/* $OpenBSD: intercept-translate.c,v 1.4 2002/06/21 15:26:06 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -121,26 +121,20 @@ int
ic_get_filename(struct intercept_translate *trans, int fd, pid_t pid,
void *addr)
{
- char buf[MAXPATHLEN];
- char *path, *name;
+ char *name;
int len;
- name = intercept_filename(fd, pid, addr);
+ name = intercept_filename(fd, pid, addr, 1);
if (name == NULL)
return (-1);
- /* If realpath fails then the filename does not exist */
- path = buf;
- if (realpath(name, path) == NULL)
- path = "<non-existant filename>";
-
- len = strlen(path) + 1;
+ len = strlen(name) + 1;
trans->trans_data = malloc(len);
if (trans->trans_data == NULL)
return (-1);
trans->trans_size = len;
- memcpy(trans->trans_data, path, len);
+ memcpy(trans->trans_data, name, len);
return (0);
}
@@ -173,7 +167,7 @@ ic_get_linkname(struct intercept_translate *trans, int fd, pid_t pid,
char *name;
int len;
- name = intercept_filename(fd, pid, addr);
+ name = intercept_filename(fd, pid, addr, 0);
if (name == NULL)
return (-1);
diff --git a/bin/systrace/intercept.c b/bin/systrace/intercept.c
index 28305c15ca1..ff95309e553 100644
--- a/bin/systrace/intercept.c
+++ b/bin/systrace/intercept.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept.c,v 1.6 2002/06/19 16:31:07 provos Exp $ */
+/* $OpenBSD: intercept.c,v 1.7 2002/06/21 15:26:06 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -362,6 +362,41 @@ intercept_read(int fd)
return (intercept.read(fd));
}
+int
+intercept_replace_init(struct intercept_replace *repl)
+{
+ memset(repl, 0, sizeof(struct intercept_replace));
+
+ return (0);
+}
+
+int
+intercept_replace_add(struct intercept_replace *repl, int off,
+ u_char *addr, size_t len)
+{
+ int ind = repl->num;
+
+ if (ind >= INTERCEPT_MAXSYSCALLARGS)
+ return (-1);
+
+ repl->ind[ind] = off;
+ repl->address[ind] = addr;
+ repl->len[ind] = len;
+
+ repl->num++;
+
+ return (0);
+}
+
+int
+intercept_replace(int fd, pid_t pid, struct intercept_replace *repl)
+{
+ if (repl->num == 0)
+ return (0);
+
+ return (intercept.replace(fd, pid, repl));
+}
+
char *
intercept_get_string(int fd, pid_t pid, void *addr)
{
@@ -391,7 +426,7 @@ intercept_get_string(int fd, pid_t pid, void *addr)
}
char *
-intercept_filename(int fd, pid_t pid, void *addr)
+intercept_filename(int fd, pid_t pid, void *addr, int userp)
{
static char cwd[2*MAXPATHLEN];
char *name;
@@ -400,10 +435,10 @@ intercept_filename(int fd, pid_t pid, void *addr)
if (name == NULL)
err(1, "%s: getstring", __func__);
- if (name[0] != '/') {
- if (intercept.getcwd(fd, pid, cwd, sizeof(cwd)) == NULL)
- err(1, "%s: getcwd", __func__);
+ if (intercept.getcwd(fd, pid, cwd, sizeof(cwd)) == NULL)
+ err(1, "%s: getcwd", __func__);
+ if (name[0] != '/') {
if (strlcat(cwd, "/", sizeof(cwd)) >= sizeof(cwd))
goto error;
if (strlcat(cwd, name, sizeof(cwd)) >= sizeof(cwd))
@@ -413,9 +448,20 @@ intercept_filename(int fd, pid_t pid, void *addr)
goto error;
}
- simplify_path(cwd);
+ name = cwd;
+ if (userp) {
+ /* If realpath fails then the filename does not exist */
+ if (realpath(cwd, cwd) == NULL)
+ name = "<non-existent filename>";
+ } else
+ simplify_path(cwd);
- return (cwd);
+
+ /* Restore working directory and change root space after realpath */
+ if (intercept.restcwd(fd) == -1)
+ err(1, "%s: restcwd", __func__);
+
+ return (name);
error:
errx(1, "%s: filename too long", __func__);
@@ -447,7 +493,7 @@ intercept_syscall(int fd, pid_t pid, int policynr, char *name, int code,
free(icpid->newname);
intercept.getarg(0, args, argsize, &addr);
- icpid->newname = strdup(intercept_filename(fd, pid, addr));
+ icpid->newname = strdup(intercept_filename(fd, pid, addr, 0));
if (icpid->newname == NULL)
err(1, "%s:%d: strdup", __func__, __LINE__);
diff --git a/bin/systrace/intercept.h b/bin/systrace/intercept.h
index 7502340fdc3..3c2c6c0d0da 100644
--- a/bin/systrace/intercept.h
+++ b/bin/systrace/intercept.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept.h,v 1.2 2002/06/10 19:16:26 provos Exp $ */
+/* $OpenBSD: intercept.h,v 1.3 2002/06/21 15:26:06 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -34,6 +34,7 @@
#include <sys/queue.h>
struct intercept_pid;
+struct intercept_replace;
struct intercept_system {
char *name;
@@ -45,12 +46,14 @@ struct intercept_system {
int (*read)(int);
int (*getsyscallnumber)(char *, char *);
char *(*getcwd)(int, pid_t, char *, size_t);
+ int (*restcwd)(int);
int (*io)(int, pid_t, int, void *, u_char *, size_t);
int (*getarg)(int, void *, int, void **);
int (*answer)(int, pid_t, short, int, short);
int (*newpolicy)(int);
int (*assignpolicy)(int, pid_t, int);
int (*policy)(int, int, int, short);
+ int (*replace)(int, pid_t, struct intercept_replace *);
void (*clonepid)(struct intercept_pid *, struct intercept_pid *);
void (*freepid)(struct intercept_pid *);
};
@@ -97,6 +100,13 @@ struct intercept_translate {
TAILQ_ENTRY(intercept_translate) next;
};
+struct intercept_replace {
+ int num;
+ int ind[INTERCEPT_MAXSYSCALLARGS];
+ u_char *address[INTERCEPT_MAXSYSCALLARGS];
+ size_t len[INTERCEPT_MAXSYSCALLARGS];
+};
+
TAILQ_HEAD(intercept_tlq, intercept_translate);
int intercept_init(void);
@@ -110,6 +120,10 @@ int intercept_newpolicy(int);
int intercept_assignpolicy(int, pid_t, int);
int intercept_modifypolicy(int, int, char *, char *, short);
+int intercept_replace_init(struct intercept_replace *);
+int intercept_replace_add(struct intercept_replace *, int, u_char *, size_t);
+int intercept_replace(int, pid_t, struct intercept_replace *);
+
int intercept_register_sccb(char *, char *,
short (*)(int, pid_t, int, char *, int, char *, void *, int,
struct intercept_tlq *, void *),
@@ -141,6 +155,6 @@ struct intercept_pid *intercept_getpid(pid_t);
int intercept_existpids(void);
char *intercept_get_string(int, pid_t, void *);
-char *intercept_filename(int, pid_t, void *);
+char *intercept_filename(int, pid_t, void *, int);
#endif /* _INTERCEPT_H_ */
diff --git a/bin/systrace/openbsd-syscalls.c b/bin/systrace/openbsd-syscalls.c
index 00c4bce7fc7..840d4d03e8c 100644
--- a/bin/systrace/openbsd-syscalls.c
+++ b/bin/systrace/openbsd-syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: openbsd-syscalls.c,v 1.5 2002/06/10 19:16:26 provos Exp $ */
+/* $OpenBSD: openbsd-syscalls.c,v 1.6 2002/06/21 15:26:06 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -393,6 +393,48 @@ obsd_modifypolicy(int fd, int num, int code, short policy)
}
int
+obsd_replace(int fd, pid_t pid, struct intercept_replace *repl)
+{
+ struct systrace_replace replace;
+ size_t len, off;
+ int i, ret;
+
+ for (i = 0, len = 0; i < repl->num; i++) {
+ len += repl->len[i];
+ }
+
+ replace.strr_pid = pid;
+ replace.strr_nrepl = repl->num;
+ replace.strr_base = malloc(len);
+ replace.strr_len = len;
+ if (replace.strr_base == NULL)
+ err(1, "%s: malloc", __func__);
+
+ for (i = 0, off = 0; i < repl->num; i++) {
+ replace.strr_argind[i] = repl->ind[i];
+ replace.strr_offlen[i] = repl->len[i];
+ if (repl->len[i] == 0) {
+ replace.strr_off[i] = (size_t)repl->address[i];
+ continue;
+ }
+
+ replace.strr_off[i] = off;
+ memcpy(replace.strr_base + off,
+ repl->address[i], repl->len[i]);
+
+ off += repl->len[i];
+ }
+
+ ret = ioctl(fd, STRIOCREPLACE, &replace);
+ if (ret == -1)
+ warn("%s: ioctl", __func__);
+
+ free(replace.strr_base);
+
+ return (ret);
+}
+
+int
obsd_io(int fd, pid_t pid, int op, void *addr, u_char *buf, size_t size)
{
struct systrace_io io;
@@ -418,11 +460,17 @@ obsd_getcwd(int fd, pid_t pid, char *buf, size_t size)
return (NULL);
path = getcwd(buf, size);
+ return (path);
+}
- if (ioctl(fd, STRIOCRESCWD, 0) == -1)
+int
+obsd_restcwd(int fd)
+{
+ int res;
+ if ((res = ioctl(fd, STRIOCRESCWD, 0)) == -1)
warn("%s: ioctl", __func__); /* XXX */
- return (path);
+ return (res);
}
int
@@ -530,12 +578,14 @@ struct intercept_system intercept = {
obsd_read,
obsd_syscall_number,
obsd_getcwd,
+ obsd_restcwd,
obsd_io,
obsd_argument,
obsd_answer,
obsd_newpolicy,
obsd_assignpolicy,
obsd_modifypolicy,
+ obsd_replace,
obsd_clonepid,
obsd_freepid,
};
diff --git a/bin/systrace/systrace.c b/bin/systrace/systrace.c
index 7a7a0af02ba..f86f952ce48 100644
--- a/bin/systrace/systrace.c
+++ b/bin/systrace/systrace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: systrace.c,v 1.18 2002/06/19 16:31:07 provos Exp $ */
+/* $OpenBSD: systrace.c,v 1.19 2002/06/21 15:26:06 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -67,6 +67,7 @@ trans_cb(int fd, pid_t pid, int policynr,
struct policy *policy;
struct intercept_translate *tl;
struct intercept_pid *ipid;
+ struct intercept_replace repl;
struct filterq *pflq = NULL;
char output[_POSIX2_LINE_MAX], *p, *line;
int size;
@@ -92,20 +93,25 @@ trans_cb(int fd, pid_t pid, int policynr,
p = output + strlen(output);
size = sizeof(output) - strlen(output);
+ intercept_replace_init(&repl);
TAILQ_FOREACH(tl, tls, next) {
if (!tl->trans_valid)
break;
line = intercept_translate_print(tl);
- if (line != NULL) {
- snprintf(p, size, ", %s: %s", tl->name, line);
- p = output + strlen(output);
- size = sizeof(output) - strlen(output);
- }
+ if (line == NULL)
+ continue;
+
+ snprintf(p, size, ", %s: %s", tl->name, line);
+ p = output + strlen(output);
+ size = sizeof(output) - strlen(output);
+
+ intercept_replace_add(&repl, tl->off,
+ tl->trans_data, tl->trans_size);
}
action = filter_evaluate(tls, pflq, &ipid->uflags);
if (action != ICPOLICY_ASK)
- goto out;
+ goto replace;
if (policy->flags & POLICY_UNSUPERVISED) {
action = ICPOLICY_NEVER;
syslog(LOG_WARNING, "user: %s, prog: %s", username, output);
@@ -124,6 +130,12 @@ trans_cb(int fd, pid_t pid, int policynr,
kill(pid, SIGKILL);
action = ICPOLICY_NEVER;
}
+ replace:
+ if (action != ICPOLICY_NEVER) {
+ /* If we can not rewrite the arguments, system call fails */
+ if (intercept_replace(fd, pid, &repl) == -1)
+ action = ICPOLICY_NEVER;
+ }
out:
return (action);
}