]> granicus.if.org Git - strace/commitdiff
Fix fanotify_mark decoding on 32-bit architectures
authorDmitry V. Levin <ldv@altlinux.org>
Sat, 10 Jan 2015 00:08:58 +0000 (00:08 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sat, 10 Jan 2015 00:40:10 +0000 (00:40 +0000)
The fanotify_mark syscall takes a 64-bit mask, and on 32-bit
architectures it is split up into two syscall arguments.

* configure.ac (AC_CHECK_FUNCS): Add fanotify_mark.
(AC_CHECK_HEADERS): Add sys/fanotify.h.
* defs.h (getllval): New prototype.
* util.c (getllval): New function based on printllval.
(printllval): Use getllval.
* fanotify.c (sys_fanotify_mark): Use getllval to properly decode
64-bit mask and two syscall arguments followed by it.
* tests/fanotify_mark.c: New file.
* tests/fanotify_mark.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add fanotify_mark.
(TESTS): Add fanotify_mark.test.
* tests/.gitignore: Add fanotify_mark.

configure.ac
defs.h
fanotify.c
tests/.gitignore
tests/Makefile.am
tests/fanotify_mark.c [new file with mode: 0644]
tests/fanotify_mark.test [new file with mode: 0755]
util.c

index 8cb72d7a7c629613b29951c0906a20a46847ec0a..1a09b98d9647d6623e7db10032c480ddb4df791a 100644 (file)
@@ -205,6 +205,7 @@ AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id],,,
 AC_LITTLE_ENDIAN_LONG_LONG
 
 AC_CHECK_FUNCS(m4_normalize([
+       fanotify_mark
        fopen64
        fork
        fputs_unlocked
@@ -239,6 +240,7 @@ AC_CHECK_HEADERS(m4_normalize([
        stropts.h
        sys/conf.h
        sys/epoll.h
+       sys/fanotify.h
        sys/filio.h
        sys/ioctl.h
        sys/poll.h
diff --git a/defs.h b/defs.h
index c865110c454de999312a92908de3d0d113b9e6b3..d0acb1959ee2eec77199ad7380ebc03eaabd86e1 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -677,6 +677,7 @@ extern int next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_b
 # define LONG_LONG(a,b) \
        ((long long)((unsigned long long)(unsigned)(b) | ((unsigned long long)(a)<<32)))
 #endif
+extern int getllval(struct tcb *, unsigned long long *, int);
 extern int printllval(struct tcb *, const char *, int);
 
 extern void printxval(const struct xlat *, const unsigned int, const char *);
index 32a366750cb32027c35f04ca89c1e8012fe6724e..02094eab2bf1cf9eb6f0cc06aa9a50183b58bc76 100644 (file)
@@ -31,6 +31,9 @@ sys_fanotify_init(struct tcb *tcp)
 int
 sys_fanotify_mark(struct tcb *tcp)
 {
+       unsigned long long mask = 0;
+       int argn;
+
        if (exiting(tcp))
                return 0;
 
@@ -38,13 +41,18 @@ sys_fanotify_mark(struct tcb *tcp)
        tprints(", ");
        printflags(fan_mark_flags, (unsigned) tcp->u_arg[1], "FAN_MARK_???");
        tprints(", ");
-       printflags(fan_event_flags, tcp->u_arg[2], "FAN_???");
+       /*
+        * the mask argument is defined as 64-bit,
+        * but kernel uses the lower 32 bits only.
+        */
+       argn = getllval(tcp, &mask, 2);
+       printflags(fan_event_flags, mask, "FAN_???");
        tprints(", ");
-       if ((int) tcp->u_arg[3] == FAN_NOFD)
+       if ((int) tcp->u_arg[argn] == FAN_NOFD)
                tprints("FAN_NOFD, ");
        else
-               print_dirfd(tcp, tcp->u_arg[3]);
-       printpath(tcp, tcp->u_arg[4]);
+               print_dirfd(tcp, tcp->u_arg[argn]);
+       printpath(tcp, tcp->u_arg[argn + 1]);
 
        return 0;
 }
index af463d08544dfded4f8df93c69b91c98d13b37ab..ce3e2103ca435b0ecf9fbe8063ddbc70e3022866 100644 (file)
@@ -1,4 +1,5 @@
 caps
+fanotify_mark
 inet-accept-connect-send-recv
 mmsg
 net-accept-connect
index b88ed55e45e18be90fdb1b75ef331f90bf2712c2..7c8f7b1303358a340ae98d4d4591557ed7713f70 100644 (file)
@@ -5,6 +5,7 @@ AM_CFLAGS = $(WARN_CFLAGS)
 check_PROGRAMS = \
        inet-accept-connect-send-recv \
        caps \
+       fanotify_mark \
        mmsg \
        net-accept-connect \
        netlink_inet_diag \
@@ -32,6 +33,7 @@ TESTS = \
        strace-f.test \
        qual_syscall.test \
        caps.test \
+       fanotify_mark.test \
        getdents.test \
        scm_rights-fd.test \
        sigaction.test \
diff --git a/tests/fanotify_mark.c b/tests/fanotify_mark.c
new file mode 100644 (file)
index 0000000..7160acd
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if defined HAVE_SYS_FANOTIFY_H && defined HAVE_FANOTIFY_MARK
+# include <sys/fanotify.h>
+int
+main(void)
+{
+       fanotify_mark(-1, FAN_MARK_ADD, FAN_MODIFY | FAN_ONDIR, -100, ".");
+       return 0;
+}
+#else
+int
+main(void)
+{
+       return 77;
+}
+#endif
diff --git a/tests/fanotify_mark.test b/tests/fanotify_mark.test
new file mode 100755 (executable)
index 0000000..c5eb4eb
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# Check fanotify_mark syscall decoding.
+
+. "${srcdir=.}/init.sh"
+
+check_prog grep
+
+./fanotify_mark || {
+       if [ $? -eq 77 ]; then
+               framework_skip_ 'fanotify_mark is not available'
+       else
+               fail_ 'fanotify_mark failed'
+       fi
+}
+
+args="-efanotify_mark ./fanotify_mark"
+$STRACE -o "$LOG" $args || {
+       cat "$LOG"
+       fail_ "$STRACE $args failed"
+}
+
+grep_log()
+{
+       local syscall="$1"; shift
+
+       LC_ALL=C grep -E -x "$syscall$*" $LOG > /dev/null || {
+               cat $LOG
+               fail_ "$STRACE $args failed to trace \"$syscall\" properly"
+       }
+}
+
+grep_log fanotify_mark '\(-1, FAN_MARK_ADD, FAN_MODIFY\|FAN_ONDIR, AT_FDCWD, "\."\) += -1.*'
+
+exit 0
diff --git a/util.c b/util.c
index 570888c8685dc749cc29606f6c6189637465263c..c7ad34f16d5aab112a7502fb5a630402aa15b2dd 100644 (file)
--- a/util.c
+++ b/util.c
@@ -242,39 +242,39 @@ printxval(const struct xlat *xlat, const unsigned int val, const char *dflt)
 }
 
 /*
- * Print 64bit argument at position arg_no and return the index of the next
- * argument.
+ * Fetch 64bit argument at position arg_no and
+ * return the index of the next argument.
  */
 int
-printllval(struct tcb *tcp, const char *format, int arg_no)
+getllval(struct tcb *tcp, unsigned long long *val, int arg_no)
 {
 #if SIZEOF_LONG > 4 && SIZEOF_LONG == SIZEOF_LONG_LONG
 # if SUPPORTED_PERSONALITIES > 1
        if (current_wordsize > 4) {
 # endif
-               tprintf(format, tcp->u_arg[arg_no]);
+               *val = tcp->u_arg[arg_no];
                arg_no++;
 # if SUPPORTED_PERSONALITIES > 1
        } else {
 #  if defined(AARCH64) || defined(POWERPC64)
                /* Align arg_no to the next even number. */
                arg_no = (arg_no + 1) & 0xe;
-#  endif
-               tprintf(format, LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]));
+#  endif /* AARCH64 || POWERPC64 */
+               *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
                arg_no += 2;
        }
-# endif /* SUPPORTED_PERSONALITIES */
+# endif /* SUPPORTED_PERSONALITIES > 1 */
 #elif SIZEOF_LONG > 4
 #  error Unsupported configuration: SIZEOF_LONG > 4 && SIZEOF_LONG_LONG > SIZEOF_LONG
 #elif defined LINUX_MIPSN32
-       tprintf(format, tcp->ext_arg[arg_no]);
+       *val = tcp->ext_arg[arg_no];
        arg_no++;
 #elif defined X32
        if (current_personality == 0) {
-               tprintf(format, tcp->ext_arg[arg_no]);
+               *val = tcp->ext_arg[arg_no];
                arg_no++;
        } else {
-               tprintf(format, LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]));
+               *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
                arg_no += 2;
        }
 #else
@@ -285,13 +285,27 @@ printllval(struct tcb *tcp, const char *format, int arg_no)
        /* Align arg_no to the next even number. */
        arg_no = (arg_no + 1) & 0xe;
 # endif
-       tprintf(format, LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]));
+       *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
        arg_no += 2;
 #endif
 
        return arg_no;
 }
 
+/*
+ * Print 64bit argument at position arg_no and
+ * return the index of the next argument.
+ */
+int
+printllval(struct tcb *tcp, const char *format, int arg_no)
+{
+       unsigned long long val = 0;
+
+       arg_no = getllval(tcp, &val, arg_no);
+       tprintf(format, val);
+       return arg_no;
+}
+
 /*
  * Interpret `xlat' as an array of flags
  * print the entries whose bits are on in `flags'