I'd love to commit this this weekend if someone can look it over and ok it.

A brief diff walk through in case it helps:

  1. The STRIOCGETCWD ioctl(2) now additionally take an openat(2)
style fd for controlling what directory the calling process chdir(2)'s
into.  Nothing in base or ports uses this ioctl(2) except for
systrace(1), so no need for backwards compat concerns.  The new logic
in systrace_getcwd() is analogous to the dirfd handling in namei()
(kern/vfs_lookup.c:169-187).

  2. There's already code in systrace(1) to handle up to two syscall
arguments (one absolute offset 'off', and a second offset 'off2'
relative to the first), and I added support for a third argument
(relative to the end of the argument list 'offend').

  3. Updated the use of STRIOCGETCWD to pass the atfd flag, and added
appropriate higher-level functions (normalize_filenameat() and
intercept_filenameat()) to accept atfd arguments.

  4. Finally, analogous to the ic_get_filename() and
ic_get_unlinkname() translation methods, I added an
ic_get_filenameat() method that can be used for all four *at(2)
link-handling conventions (always follow links, never follow links,
default to following links, default to not following links) based on
the value of .user (default behavior) and .offend (whether a flag is
allowed).

ok?

On Wed, Aug 31, 2011 at 6:26 PM, Matthew Dempsky <matt...@dempsky.org> wrote:
> 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