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.
This commit is contained in:
Дмитрий Левин 2015-01-10 00:08:58 +00:00
parent 197db577e8
commit 1ea64735fc
8 changed files with 97 additions and 15 deletions

View 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

1
defs.h
View File

@ -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 *);

View 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;
}

1
tests/.gitignore vendored
View File

@ -1,4 +1,5 @@
caps
fanotify_mark
inet-accept-connect-send-recv
mmsg
net-accept-connect

View 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 \

19
tests/fanotify_mark.c Normal file
View File

@ -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

35
tests/fanotify_mark.test Executable file
View File

@ -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

36
util.c
View File

@ -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'