From: Dmitry V. Levin Date: Sat, 10 Jan 2015 00:08:58 +0000 (+0000) Subject: Fix fanotify_mark decoding on 32-bit architectures X-Git-Tag: v4.10~236 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1ea64735fc2cdd4d2814a6455b50f6989c7f1d34;p=strace Fix fanotify_mark decoding on 32-bit architectures 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. --- diff --git a/configure.ac b/configure.ac index 8cb72d7a..1a09b98d 100644 --- a/configure.ac +++ b/configure.ac @@ -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 c865110c..d0acb195 100644 --- 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 *); diff --git a/fanotify.c b/fanotify.c index 32a36675..02094eab 100644 --- a/fanotify.c +++ b/fanotify.c @@ -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; } diff --git a/tests/.gitignore b/tests/.gitignore index af463d08..ce3e2103 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,4 +1,5 @@ caps +fanotify_mark inet-accept-connect-send-recv mmsg net-accept-connect diff --git a/tests/Makefile.am b/tests/Makefile.am index b88ed55e..7c8f7b13 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 00000000..7160acdb --- /dev/null +++ b/tests/fanotify_mark.c @@ -0,0 +1,19 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if defined HAVE_SYS_FANOTIFY_H && defined HAVE_FANOTIFY_MARK +# include +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 index 00000000..c5eb4eb7 --- /dev/null +++ b/tests/fanotify_mark.test @@ -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 570888c8..c7ad34f1 100644 --- 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'