diff options
author | Niels Provos <provos@cvs.openbsd.org> | 2002-06-21 15:26:07 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 2002-06-21 15:26:07 +0000 |
commit | eab57a6ade26fd4b5b7c5642326ec2de9c01f56d (patch) | |
tree | 855c6a054cf99b284c5c766f6f6ce524208a106c | |
parent | ab636641a14766506bddd6c38591baa9f6c9b4ac (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.c | 18 | ||||
-rw-r--r-- | bin/systrace/intercept.c | 62 | ||||
-rw-r--r-- | bin/systrace/intercept.h | 18 | ||||
-rw-r--r-- | bin/systrace/openbsd-syscalls.c | 56 | ||||
-rw-r--r-- | bin/systrace/systrace.c | 26 |
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); } |