Diff below adds support to systrace(1) for the new *at(2) system
calls.  (I'll send a followup diff for the ports tree.)

It's received some light testing from jasper@ and myself, so it could
now use some wider testing as well as an extra set of eyes to review
the code.

Index: sys/dev/systrace.h
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/sys/dev/systrace.h,v
retrieving revision 1.22
diff -u -p -r1.22 systrace.h
--- sys/dev/systrace.h  22 Jun 2011 01:32:16 -0000      1.22
+++ sys/dev/systrace.h  26 Aug 2011 01:30:05 -0000
@@ -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)
Index: sys/dev/systrace.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/sys/dev/systrace.c,v
retrieving revision 1.59
diff -u -p -r1.59 systrace.c
--- sys/dev/systrace.c  11 Jul 2011 15:40:47 -0000      1.59
+++ sys/dev/systrace.c  26 Aug 2011 01:31:28 -0000
@@ -158,7 +158,7 @@ int systrace_io(struct str_process *, st
 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 
        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 
                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 
                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
 }
 
 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, s
        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);
Index: bin/systrace/intercept-translate.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/bin/systrace/intercept-translate.c,v
retrieving revision 1.13
diff -u -p -r1.13 intercept-translate.c
--- bin/systrace/intercept-translate.c  10 Jun 2006 07:19:13 -0000      1.13
+++ bin/systrace/intercept-translate.c  1 Sep 2011 01:17:12 -0000
@@ -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_tra
                        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_trans
 }
 
 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)
 {
@@ -357,6 +401,36 @@ struct intercept_translate ic_translate_
 struct intercept_translate ic_translate_unlinkname = {
        "filename",
        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 = {
Index: bin/systrace/intercept.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/bin/systrace/intercept.c,v
retrieving revision 1.56
diff -u -p -r1.56 intercept.c
--- bin/systrace/intercept.c    20 Apr 2010 21:56:52 -0000      1.56
+++ bin/systrace/intercept.c    26 Aug 2011 04:46:51 -0000
@@ -589,6 +589,12 @@ intercept_get_string(int fd, pid_t pid, 
 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, vo
        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, vo
 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, ch
        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:
Index: bin/systrace/intercept.h
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/bin/systrace/intercept.h,v
retrieving revision 1.24
diff -u -p -r1.24 intercept.h
--- bin/systrace/intercept.h    2 Jul 2006 12:34:15 -0000       1.24
+++ bin/systrace/intercept.h    1 Sep 2011 01:16:01 -0000
@@ -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_tra
 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,
Index: bin/systrace/openbsd-syscalls.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/bin/systrace/openbsd-syscalls.c,v
retrieving revision 1.40
diff -u -p -r1.40 openbsd-syscalls.c
--- bin/systrace/openbsd-syscalls.c     4 Jul 2011 22:59:42 -0000       1.40
+++ bin/systrace/openbsd-syscalls.c     26 Aug 2011 04:41:42 -0000
@@ -110,7 +110,7 @@ static int obsd_assignpolicy(int, pid_t,
 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 
 }
 
 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
Index: bin/systrace/register.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/bin/systrace/register.c,v
retrieving revision 1.22
diff -u -p -r1.22 register.c
--- bin/systrace/register.c     14 Aug 2006 07:24:55 -0000      1.22
+++ bin/systrace/register.c     26 Aug 2011 05:48:04 -0000
@@ -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);

Reply via email to