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:
parent
197db577e8
commit
1ea64735fc
@ -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
1
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 *);
|
||||
|
16
fanotify.c
16
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;
|
||||
}
|
||||
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
caps
|
||||
fanotify_mark
|
||||
inet-accept-connect-send-recv
|
||||
mmsg
|
||||
net-accept-connect
|
||||
|
@ -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
19
tests/fanotify_mark.c
Normal 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
35
tests/fanotify_mark.test
Executable 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
36
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'
|
||||
|
Loading…
x
Reference in New Issue
Block a user