diff options
author | Matthew Dempsky <matthew@cvs.openbsd.org> | 2011-09-18 23:24:15 +0000 |
---|---|---|
committer | Matthew Dempsky <matthew@cvs.openbsd.org> | 2011-09-18 23:24:15 +0000 |
commit | 01828fa1f01fd1c82399b056e2c7250d308c56df (patch) | |
tree | 3748a26e81c4f2f6851f7a751eb44d6502ab2b97 | |
parent | 7fbcb0d21f1e3057dc3a3c665ca09626fbed9de4 (diff) |
Add support for *at(2) system calls to systrace(1).
ok deraadt@, sthen@, jasper@
-rw-r--r-- | bin/systrace/intercept-translate.c | 78 | ||||
-rw-r--r-- | bin/systrace/intercept.c | 18 | ||||
-rw-r--r-- | bin/systrace/intercept.h | 12 | ||||
-rw-r--r-- | bin/systrace/openbsd-syscalls.c | 11 | ||||
-rw-r--r-- | bin/systrace/register.c | 77 | ||||
-rw-r--r-- | sys/dev/systrace.c | 30 | ||||
-rw-r--r-- | sys/dev/systrace.h | 9 |
7 files changed, 214 insertions, 21 deletions
diff --git a/bin/systrace/intercept-translate.c b/bin/systrace/intercept-translate.c index b2bf3acfa66..0a0b12ec522 100644 --- a/bin/systrace/intercept-translate.c +++ b/bin/systrace/intercept-translate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intercept-translate.c,v 1.13 2006/06/10 07:19:13 sturm Exp $ */ +/* $OpenBSD: intercept-translate.c,v 1.14 2011/09/18 23:24:14 matthew Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -33,6 +33,7 @@ #include <sys/param.h> #include <sys/tree.h> #include <sys/socket.h> +#include <fcntl.h> #include <inttypes.h> #include <limits.h> #include <stdio.h> @@ -75,7 +76,7 @@ int intercept_translate(struct intercept_translate *trans, int fd, pid_t pid, int off, void *args, int argsize) { - void *addr, *addr2; + void *addr, *addr2, *addrend; ic_trans_free(trans); @@ -87,6 +88,12 @@ intercept_translate(struct intercept_translate *trans, return (-1); trans->trans_addr2 = addr2; } + if (trans->offend) { + if (intercept.getarg(argsize + trans->offend, + args, argsize, &addrend) == -1) + return (-1); + trans->trans_addrend = addrend; + } trans->trans_valid = 1; trans->trans_addr = addr; @@ -221,6 +228,43 @@ ic_get_unlinkname(struct intercept_translate *trans, int fd, pid_t pid, } static int +ic_get_filenameat(struct intercept_translate *trans, int fd, pid_t pid, + void *addr) +{ + char *name; + size_t len; + int atfd = (intptr_t)trans->trans_addr2; + int follow = (intptr_t)trans->user; + int userp; + + if (trans->offend) { + int flag = (intptr_t)trans->trans_addrend; + if ((flag & ~(AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)) != 0) + return (-1); + if ((flag & follow) != 0) + return (-1); + if (flag != 0) + follow = flag; + } + + userp = (follow == AT_SYMLINK_FOLLOW) ? ICLINK_ALL : ICLINK_NOLAST; + name = intercept_filenameat(fd, pid, atfd, addr, userp, NULL); + if (name == NULL) + return (-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, name, len); + trans->trans_flags = ICTRANS_NOLINKS; + + return (0); +} + +static int ic_get_sockaddr(struct intercept_translate *trans, int fd, pid_t pid, void *addr) { @@ -359,6 +403,36 @@ struct intercept_translate ic_translate_unlinkname = { ic_get_unlinkname, ic_print_filename, }; +struct intercept_translate ic_translate_filenameat = { + "filename", + ic_get_filenameat, ic_print_filename, + .off2 = -1, + .user = (void *)AT_SYMLINK_FOLLOW, +}; + +struct intercept_translate ic_translate_unlinknameat = { + "filename", + ic_get_filenameat, ic_print_filename, + .off2 = -1, + .user = (void *)AT_SYMLINK_NOFOLLOW, +}; + +struct intercept_translate ic_translate_filenameatflag = { + "filename", + ic_get_filenameat, ic_print_filename, + .off2 = -1, + .offend = -1, + .user = (void *)AT_SYMLINK_FOLLOW, +}; + +struct intercept_translate ic_translate_unlinknameatflag = { + "filename", + ic_get_filenameat, ic_print_filename, + .off2 = -1, + .offend = -1, + .user = (void *)AT_SYMLINK_NOFOLLOW, +}; + struct intercept_translate ic_translate_connect = { "sockaddr", ic_get_sockaddr, ic_print_sockaddr, diff --git a/bin/systrace/intercept.c b/bin/systrace/intercept.c index dee54f3bd6d..6059df4e959 100644 --- a/bin/systrace/intercept.c +++ b/bin/systrace/intercept.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intercept.c,v 1.56 2010/04/20 21:56:52 tedu Exp $ */ +/* $OpenBSD: intercept.c,v 1.57 2011/09/18 23:24:14 matthew Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -589,6 +589,12 @@ intercept_get_string(int fd, pid_t pid, void *addr) char * intercept_filename(int fd, pid_t pid, void *addr, int userp, char *before) { + return (intercept_filenameat(fd, pid, AT_FDCWD, addr, userp, before)); +} + +char * +intercept_filenameat(int fd, pid_t pid, int atfd, void *addr, int userp, char *before) +{ char *name; if ((name = intercept_get_string(fd, pid, addr)) == NULL) @@ -597,7 +603,7 @@ intercept_filename(int fd, pid_t pid, void *addr, int userp, char *before) if (before != NULL) strlcpy(before, name, MAXPATHLEN); - if ((name = normalize_filename(fd, pid, name, userp)) == NULL) + if ((name = normalize_filenameat(fd, pid, atfd, name, userp)) == NULL) goto abort; return (name); @@ -615,6 +621,12 @@ intercept_filename(int fd, pid_t pid, void *addr, int userp, char *before) char * normalize_filename(int fd, pid_t pid, char *name, int userp) { + return (normalize_filenameat(fd, pid, AT_FDCWD, name, userp)); +} + +char * +normalize_filenameat(int fd, pid_t pid, int atfd, char *name, int userp) +{ static char cwd[2*MAXPATHLEN]; int havecwd = 0; @@ -625,7 +637,7 @@ normalize_filename(int fd, pid_t pid, char *name, int userp) if (strcmp(name, "") == 0) return (name); - if (fd != -1 && intercept.setcwd(fd, pid) == -1) { + if (fd != -1 && intercept.setcwd(fd, pid, atfd) == -1) { if (errno == EBUSY) return (NULL); getcwderr: diff --git a/bin/systrace/intercept.h b/bin/systrace/intercept.h index d371dfb9e31..9a2f23b50ed 100644 --- a/bin/systrace/intercept.h +++ b/bin/systrace/intercept.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intercept.h,v 1.24 2006/07/02 12:34:15 sturm Exp $ */ +/* $OpenBSD: intercept.h,v 1.25 2011/09/18 23:24:14 matthew Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -47,7 +47,7 @@ struct intercept_system { int (*report)(int, pid_t); int (*read)(int); int (*getsyscallnumber)(const char *, const char *); - int (*setcwd)(int, pid_t); + int (*setcwd)(int, pid_t, int); int (*restcwd)(int); int (*io)(int, pid_t, int, void *, u_char *, size_t); int (*getarg)(int, void *, int, void **); @@ -118,10 +118,12 @@ struct intercept_translate { int (*translate)(struct intercept_translate *, int, pid_t, void *); int (*print)(char *, size_t, struct intercept_translate *); int off2; + int offend; int off; u_char trans_valid; void *trans_addr; void *trans_addr2; + void *trans_addrend; void *trans_data; size_t trans_size; char *trans_print; @@ -184,6 +186,10 @@ extern struct intercept_translate ic_translate_string; extern struct intercept_translate ic_translate_filename; extern struct intercept_translate ic_translate_linkname; extern struct intercept_translate ic_translate_unlinkname; +extern struct intercept_translate ic_translate_filenameat; +extern struct intercept_translate ic_translate_unlinknameat; +extern struct intercept_translate ic_translate_filenameatflag; +extern struct intercept_translate ic_translate_unlinknameatflag; extern struct intercept_translate ic_translate_connect; extern struct intercept_translate ic_translate_sendmsg; @@ -194,7 +200,9 @@ int intercept_existpids(void); char *intercept_get_string(int, pid_t, void *); char *normalize_filename(int, pid_t, char *, int); +char *normalize_filenameat(int, pid_t, int, char *, int); char *intercept_filename(int, pid_t, void *, int, char *); +char *intercept_filenameat(int, pid_t, int, 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 b78ad3eebbd..a8f2fc5652b 100644 --- a/bin/systrace/openbsd-syscalls.c +++ b/bin/systrace/openbsd-syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: openbsd-syscalls.c,v 1.40 2011/07/04 22:59:42 tedu Exp $ */ +/* $OpenBSD: openbsd-syscalls.c,v 1.41 2011/09/18 23:24:14 matthew Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -110,7 +110,7 @@ static int obsd_assignpolicy(int, pid_t, int); static int obsd_modifypolicy(int, int, int, short); static int obsd_replace(int, pid_t, u_int16_t, struct intercept_replace *); static int obsd_io(int, pid_t, int, void *, u_char *, size_t); -static int obsd_setcwd(int, pid_t); +static int obsd_setcwd(int, pid_t, int); static int obsd_restcwd(int); static int obsd_argument(int, void *, int, void **); static int obsd_read(int); @@ -488,9 +488,12 @@ obsd_io(int fd, pid_t pid, int op, void *addr, u_char *buf, size_t size) } static int -obsd_setcwd(int fd, pid_t pid) +obsd_setcwd(int fd, pid_t pid, int atfd) { - return (ioctl(fd, STRIOCGETCWD, &pid)); + struct systrace_getcwd gd; + gd.strgd_pid = pid; + gd.strgd_atfd = atfd; + return (ioctl(fd, STRIOCGETCWD, &gd)); } static int diff --git a/bin/systrace/register.c b/bin/systrace/register.c index 83731601a7b..1d68d06c513 100644 --- a/bin/systrace/register.c +++ b/bin/systrace/register.c @@ -1,4 +1,4 @@ -/* $OpenBSD: register.c,v 1.22 2006/08/14 07:24:55 ray Exp $ */ +/* $OpenBSD: register.c,v 1.23 2011/09/18 23:24:14 matthew Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -189,6 +189,81 @@ systrace_initcb(void) X(intercept_register_sccb("native", "mprotect", trans_cb, NULL)); intercept_register_translation("native", "mprotect", 2, &ic_memprot); + X(intercept_register_sccb("native", "openat", trans_cb, NULL)); + tl = intercept_register_translation("native", "openat", 1, + &ic_translate_filenameat); + intercept_register_translation("native", "openat", 2, &ic_oflags); + alias = systrace_new_alias("native", "openat", "native", "fswrite"); + systrace_alias_add_trans(alias, tl); + + X(intercept_register_sccb("native", "mkdirat", trans_cb, NULL)); + tl = intercept_register_translation("native", "mkdirat", 1, + &ic_translate_unlinknameat); + alias = systrace_new_alias("native", "mkdirat", "native", "fswrite"); + systrace_alias_add_trans(alias, tl); + + X(intercept_register_sccb("native", "mkfifoat", trans_cb, NULL)); + tl = intercept_register_translation("native", "mkfifoat", 1, + &ic_translate_unlinknameat); + intercept_register_translation("native", "mkfifoat", 2, &ic_modeflags); + alias = systrace_new_alias("native", "mkfifoat", "native", "fswrite"); + systrace_alias_add_trans(alias, tl); + + X(intercept_register_sccb("native", "mknodat", trans_cb, NULL)); + intercept_register_translation("native", "mknodat", 1, + &ic_translate_unlinknameat); + intercept_register_translation("native", "mknodat", 2, &ic_modeflags); + + X(intercept_register_sccb("native", "symlinkat", trans_cb, NULL)); + intercept_register_transstring("native", "symlinkat", 0); + intercept_register_translation("native", "symlinkat", 2, + &ic_translate_unlinknameat); + + X(intercept_register_sccb("native", "faccessat", trans_cb, NULL)); + tl = intercept_register_translation("native", "faccessat", 1, + &ic_translate_filenameat); + alias = systrace_new_alias("native", "faccessat", "native", "fsread"); + systrace_alias_add_trans(alias, tl); + + X(intercept_register_sccb("native", "unlinkat", trans_cb, NULL)); + tl = intercept_register_translation("native", "unlinkat", 1, + &ic_translate_unlinknameat); + alias = systrace_new_alias("native", "unlinkat", "native", "fswrite"); + systrace_alias_add_trans(alias, tl); + + X(intercept_register_sccb("native", "readlinkat", trans_cb, NULL)); + tl = intercept_register_translation("native", "readlinkat", 1, + &ic_translate_unlinknameat); + alias = systrace_new_alias("native", "readlinkat", "native", "fsread"); + systrace_alias_add_trans(alias, tl); + + X(intercept_register_sccb("native", "renameat", trans_cb, NULL)); + intercept_register_translation("native", "renameat", 1, + &ic_translate_unlinknameat); + intercept_register_translation("native", "renameat", 3, + &ic_translate_unlinknameat); + + X(intercept_register_sccb("native", "fchownat", trans_cb, NULL)); + intercept_register_translation("native", "fchownat", 1, + &ic_translate_filenameatflag); + intercept_register_translation("native", "fchownat", 2, &ic_uidt); + intercept_register_translation("native", "fchownat", 3, &ic_gidt); + X(intercept_register_sccb("native", "fchmodat", trans_cb, NULL)); + intercept_register_translation("native", "fchmodat", 1, + &ic_translate_filenameatflag); + intercept_register_translation("native", "fchmodat", 2, &ic_modeflags); + X(intercept_register_sccb("native", "fstatat", trans_cb, NULL)); + tl = intercept_register_translation("native", "fstatat", 1, + &ic_translate_filenameatflag); + alias = systrace_new_alias("native", "fstatat", "native", "fsread"); + systrace_alias_add_trans(alias, tl); + + X(intercept_register_sccb("native", "linkat", trans_cb, NULL)); + intercept_register_translation("native", "linkat", 1, + &ic_translate_unlinknameatflag); + intercept_register_translation("native", "linkat", 3, + &ic_translate_unlinknameat); + X(intercept_register_sccb("linux", "open", trans_cb, NULL)); tl = intercept_register_translink("linux", "open", 0); intercept_register_translation("linux", "open", 1, &ic_linux_oflags); diff --git a/sys/dev/systrace.c b/sys/dev/systrace.c index 1f47f233f40..09147c791a8 100644 --- a/sys/dev/systrace.c +++ b/sys/dev/systrace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.c,v 1.59 2011/07/11 15:40:47 guenther Exp $ */ +/* $OpenBSD: systrace.c,v 1.60 2011/09/18 23:24:14 matthew Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -158,7 +158,7 @@ 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 *); int systrace_replace(struct str_process *, size_t, register_t []); -int systrace_getcwd(struct fsystrace *, struct str_process *); +int systrace_getcwd(struct fsystrace *, struct str_process *, int); int systrace_fname(struct str_process *, caddr_t, size_t); void systrace_replacefree(struct str_process *); @@ -267,6 +267,7 @@ systracef_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p) struct filedesc *fdp; struct str_process *strp; pid_t pid = 0; + int atfd = -1; switch (cmd) { case FIONBIO: @@ -299,11 +300,14 @@ systracef_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p) if (!pid) ret = EINVAL; break; - case STRIOCGETCWD: - pid = *(pid_t *)data; + case STRIOCGETCWD: { + struct systrace_getcwd *gd = (struct systrace_getcwd *)data; + pid = gd->strgd_pid; if (!pid) ret = EINVAL; + atfd = gd->strgd_atfd; break; + } case STRIOCATTACH: case STRIOCRESCWD: case STRIOCPOLICY: @@ -386,7 +390,7 @@ systracef_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p) fst->fd_cdir = fst->fd_rdir = NULL; break; case STRIOCGETCWD: - ret = systrace_getcwd(fst, strp); + ret = systrace_getcwd(fst, strp, atfd); break; default: ret = ENOTTY; @@ -1107,9 +1111,10 @@ systrace_processready(struct str_process *strp) } int -systrace_getcwd(struct fsystrace *fst, struct str_process *strp) +systrace_getcwd(struct fsystrace *fst, struct str_process *strp, int atfd) { struct filedesc *myfdp, *fdp; + struct vnode *dvp; int error; DPRINTF(("%s: %d\n", __func__, strp->pid)); @@ -1123,12 +1128,23 @@ systrace_getcwd(struct fsystrace *fst, struct str_process *strp) if (myfdp == NULL || fdp == NULL) return (EINVAL); + if (atfd == AT_FDCWD) + dvp = fdp->fd_cdir; + else { + struct file *fp = fd_getfile(fdp, atfd); + if (fp == NULL || fp->f_type != DTYPE_VNODE) + return (EINVAL); + dvp = (struct vnode *)fp->f_data; + if (dvp->v_type != VDIR) + return (EINVAL); + } + /* Store our current values */ fst->fd_pid = strp->pid; fst->fd_cdir = myfdp->fd_cdir; fst->fd_rdir = myfdp->fd_rdir; - if ((myfdp->fd_cdir = fdp->fd_cdir) != NULL) + if ((myfdp->fd_cdir = dvp) != NULL) vref(myfdp->fd_cdir); if ((myfdp->fd_rdir = fdp->fd_rdir) != NULL) vref(myfdp->fd_rdir); diff --git a/sys/dev/systrace.h b/sys/dev/systrace.h index 9af22c05cf8..18a9b9e0429 100644 --- a/sys/dev/systrace.h +++ b/sys/dev/systrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.h,v 1.22 2011/06/22 01:32:16 djm Exp $ */ +/* $OpenBSD: systrace.h,v 1.23 2011/09/18 23:24:14 matthew Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -167,6 +167,11 @@ struct systrace_inject { pid_t stri_pid; }; +struct systrace_getcwd { + pid_t strgd_pid; + int strgd_atfd; +}; + #define STRIOCCLONE _IOR('s', 100, int) #define SYSTR_CLONE STRIOCCLONE #define STRIOCATTACH _IOW('s', 101, pid_t) @@ -174,7 +179,7 @@ struct systrace_inject { #define STRIOCANSWER _IOW('s', 103, struct systrace_answer) #define STRIOCIO _IOWR('s', 104, struct systrace_io) #define STRIOCPOLICY _IOWR('s', 105, struct systrace_policy) -#define STRIOCGETCWD _IOW('s', 106, pid_t) +#define STRIOCGETCWD _IOW('s', 106, struct systrace_getcwd) #define STRIOCRESCWD _IO('s', 107) #define STRIOCREPORT _IOW('s', 108, pid_t) #define STRIOCREPLACE _IOW('s', 109, struct systrace_replace) |