diff options
author | Dmitry V. Levin <ldv@altlinux.org> | 2014-02-05 04:13:18 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2014-02-05 04:55:21 +0000 |
commit | 99db95dd039d8fd700e7759bf4969abb55b979b9 (patch) | |
tree | 80c0c685dbf3a064a9455628f76fd4d86b9c3116 | |
parent | 594527353359d9a6aad516992e09c393e11f3bd2 (diff) | |
download | strace-99db95dd039d8fd700e7759bf4969abb55b979b9.tar.gz strace-99db95dd039d8fd700e7759bf4969abb55b979b9.tar.bz2 strace-99db95dd039d8fd700e7759bf4969abb55b979b9.tar.xz |
Implement fanotify_init and fanotify_mark decoding
* fanotify.c: New file.
* linux/fanotify.h: Likewise.
* Makefile.am (strace_SOURCES): Add fanotify.c.
(EXTRA_DIST): Add linux/fanotify.h.
* defs.h (print_dirfd): New prototype.
* file.c (print_dirfd): Export.
* linux/dummy.h (sys_fanotify_init, sys_fanotify_mark): Remove.
* linux/syscall.h (sys_fanotify_init, sys_fanotify_mark): New
prototypes.
* pathtrace.c (pathtrace_match): Handle sys_fanotify_init and
sys_fanotify_mark.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | defs.h | 1 | ||||
-rw-r--r-- | fanotify.c | 86 | ||||
-rw-r--r-- | file.c | 2 | ||||
-rw-r--r-- | linux/dummy.h | 2 | ||||
-rw-r--r-- | linux/fanotify.h | 116 | ||||
-rw-r--r-- | linux/syscall.h | 2 | ||||
-rw-r--r-- | pathtrace.c | 8 |
8 files changed, 215 insertions, 4 deletions
diff --git a/Makefile.am b/Makefile.am index 2ba30f6..e9e4d21 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,6 +20,7 @@ strace_SOURCES = \ block.c \ count.c \ desc.c \ + fanotify.c \ file.c \ io.c \ ioctl.c \ @@ -94,6 +95,7 @@ EXTRA_DIST = \ linux/bfin/syscallent.h \ linux/dummy.h \ linux/errnoent.h \ + linux/fanotify.h \ linux/hppa/errnoent.h \ linux/hppa/ioctlent.h.in \ linux/hppa/signalent.h \ @@ -678,6 +678,7 @@ extern void printsiginfo(siginfo_t *, int); extern void printsiginfo_at(struct tcb *tcp, long addr); #endif extern void printfd(struct tcb *, int); +extern void print_dirfd(struct tcb *, int); extern void printsock(struct tcb *, long, int); extern void print_sock_optmgmt(struct tcb *, long, int); extern void printrusage(struct tcb *, long); diff --git a/fanotify.c b/fanotify.c new file mode 100644 index 0000000..c8a7e37 --- /dev/null +++ b/fanotify.c @@ -0,0 +1,86 @@ +#include "defs.h" +#include <linux/fanotify.h> + +static const struct xlat fan_classes[] = { + XLAT(FAN_CLASS_NOTIF), + XLAT(FAN_CLASS_CONTENT), + XLAT(FAN_CLASS_PRE_CONTENT), + XLAT_END +}; + +static const struct xlat fan_init_flags[] = { + XLAT(FAN_CLOEXEC), + XLAT(FAN_NONBLOCK), + XLAT(FAN_UNLIMITED_QUEUE), + XLAT(FAN_UNLIMITED_MARKS), + XLAT_END +}; + +int +sys_fanotify_init(struct tcb *tcp) +{ + unsigned flags; + + if (exiting(tcp)) + return 0; + + flags = tcp->u_arg[0]; + printxval(fan_classes, flags & FAN_ALL_CLASS_BITS, "FAN_CLASS_???"); + flags &= ~FAN_ALL_CLASS_BITS; + if (flags) { + tprints("|"); + printflags(fan_init_flags, flags, "FAN_???"); + } + tprints(", "); + tprint_open_modes((unsigned) tcp->u_arg[1]); + + return 0; +} + +static const struct xlat fan_mark_flags[] = { + XLAT(FAN_MARK_ADD), + XLAT(FAN_MARK_REMOVE), + XLAT(FAN_MARK_DONT_FOLLOW), + XLAT(FAN_MARK_ONLYDIR), + XLAT(FAN_MARK_MOUNT), + XLAT(FAN_MARK_IGNORED_MASK), + XLAT(FAN_MARK_IGNORED_SURV_MODIFY), + XLAT(FAN_MARK_FLUSH), + XLAT_END +}; + +static const struct xlat fan_event_flags[] = { + XLAT(FAN_ACCESS), + XLAT(FAN_MODIFY), + XLAT(FAN_CLOSE), + XLAT(FAN_CLOSE_WRITE), + XLAT(FAN_CLOSE_NOWRITE), + XLAT(FAN_OPEN), + XLAT(FAN_Q_OVERFLOW), + XLAT(FAN_OPEN_PERM), + XLAT(FAN_ACCESS_PERM), + XLAT(FAN_ONDIR), + XLAT(FAN_EVENT_ON_CHILD), + XLAT_END +}; + +int +sys_fanotify_mark(struct tcb *tcp) +{ + if (exiting(tcp)) + return 0; + + printfd(tcp, tcp->u_arg[0]); + tprints(", "); + printflags(fan_mark_flags, (unsigned) tcp->u_arg[1], "FAN_MARK_???"); + tprints(", "); + printflags(fan_event_flags, tcp->u_arg[2], "FAN_???"); + tprints(", "); + if ((int) tcp->u_arg[3] == FAN_NOFD) + tprints("FAN_NOFD, "); + else + print_dirfd(tcp, tcp->u_arg[3]); + printpath(tcp, tcp->u_arg[4]); + + return 0; +} @@ -332,7 +332,7 @@ const struct xlat open_mode_flags[] = { /* The fd is an "int", so when decoding x86 on x86_64, we need to force sign * extension to get the right value. We do this by declaring fd as int here. */ -static void +void print_dirfd(struct tcb *tcp, int fd) { if (fd == AT_FDCWD) diff --git a/linux/dummy.h b/linux/dummy.h index 6af5ec7..979ed37 100644 --- a/linux/dummy.h +++ b/linux/dummy.h @@ -33,8 +33,6 @@ /* still unfinished */ #define sys_add_key printargs -#define sys_fanotify_init printargs -#define sys_fanotify_mark printargs #define sys_finit_module printargs #define sys_ioperm printargs #define sys_iopl printargs diff --git a/linux/fanotify.h b/linux/fanotify.h new file mode 100644 index 0000000..030508d --- /dev/null +++ b/linux/fanotify.h @@ -0,0 +1,116 @@ +#ifndef _UAPI_LINUX_FANOTIFY_H +#define _UAPI_LINUX_FANOTIFY_H + +#include <linux/types.h> + +/* the following events that user-space can register for */ +#define FAN_ACCESS 0x00000001 /* File was accessed */ +#define FAN_MODIFY 0x00000002 /* File was modified */ +#define FAN_CLOSE_WRITE 0x00000008 /* Writtable file closed */ +#define FAN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ +#define FAN_OPEN 0x00000020 /* File was opened */ + +#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ + +#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ +#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ + +#define FAN_ONDIR 0x40000000 /* event occurred against dir */ + +#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */ + +/* helper events */ +#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */ + +/* flags used for fanotify_init() */ +#define FAN_CLOEXEC 0x00000001 +#define FAN_NONBLOCK 0x00000002 + +/* These are NOT bitwise flags. Both bits are used togther. */ +#define FAN_CLASS_NOTIF 0x00000000 +#define FAN_CLASS_CONTENT 0x00000004 +#define FAN_CLASS_PRE_CONTENT 0x00000008 +#define FAN_ALL_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \ + FAN_CLASS_PRE_CONTENT) + +#define FAN_UNLIMITED_QUEUE 0x00000010 +#define FAN_UNLIMITED_MARKS 0x00000020 + +#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ + FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\ + FAN_UNLIMITED_MARKS) + +/* flags used for fanotify_modify_mark() */ +#define FAN_MARK_ADD 0x00000001 +#define FAN_MARK_REMOVE 0x00000002 +#define FAN_MARK_DONT_FOLLOW 0x00000004 +#define FAN_MARK_ONLYDIR 0x00000008 +#define FAN_MARK_MOUNT 0x00000010 +#define FAN_MARK_IGNORED_MASK 0x00000020 +#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040 +#define FAN_MARK_FLUSH 0x00000080 + +#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ + FAN_MARK_REMOVE |\ + FAN_MARK_DONT_FOLLOW |\ + FAN_MARK_ONLYDIR |\ + FAN_MARK_MOUNT |\ + FAN_MARK_IGNORED_MASK |\ + FAN_MARK_IGNORED_SURV_MODIFY |\ + FAN_MARK_FLUSH) + +/* + * All of the events - we build the list by hand so that we can add flags in + * the future and not break backward compatibility. Apps will get only the + * events that they originally wanted. Be sure to add new events here! + */ +#define FAN_ALL_EVENTS (FAN_ACCESS |\ + FAN_MODIFY |\ + FAN_CLOSE |\ + FAN_OPEN) + +/* + * All events which require a permission response from userspace + */ +#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\ + FAN_ACCESS_PERM) + +#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\ + FAN_ALL_PERM_EVENTS |\ + FAN_Q_OVERFLOW) + +#define FANOTIFY_METADATA_VERSION 3 + +struct fanotify_event_metadata { + __u32 event_len; + __u8 vers; + __u8 reserved; + __u16 metadata_len; + __aligned_u64 mask; + __s32 fd; + __s32 pid; +}; + +struct fanotify_response { + __s32 fd; + __u32 response; +}; + +/* Legit userspace responses to a _PERM event */ +#define FAN_ALLOW 0x01 +#define FAN_DENY 0x02 +/* No fd set in event */ +#define FAN_NOFD -1 + +/* Helper functions to deal with fanotify_event_metadata buffers */ +#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) + +#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \ + (struct fanotify_event_metadata*)(((char *)(meta)) + \ + (meta)->event_len)) + +#define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \ + (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \ + (long)(meta)->event_len <= (long)(len)) + +#endif /* _UAPI_LINUX_FANOTIFY_H */ diff --git a/linux/syscall.h b/linux/syscall.h index 502e8eb..d2ba126 100644 --- a/linux/syscall.h +++ b/linux/syscall.h @@ -66,6 +66,8 @@ int sys_faccessat(); int sys_fadvise64(); int sys_fadvise64_64(); int sys_fallocate(); +int sys_fanotify_init(); +int sys_fanotify_mark(); int sys_fchmod(); int sys_fchmodat(); int sys_fchown(); diff --git a/pathtrace.c b/pathtrace.c index f6c3b80..9fb99c4 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -251,6 +251,12 @@ pathtrace_match(struct tcb *tcp) return fdmatch(tcp, tcp->u_arg[2]); } + if (s->sys_func == sys_fanotify_mark) { + /* x, x, x, fd, path */ + return fdmatch(tcp, tcp->u_arg[3]) || + upathmatch(tcp, tcp->u_arg[4]); + } + if (s->sys_func == sys_select || s->sys_func == sys_oldselect || s->sys_func == sys_pselect6) @@ -341,7 +347,7 @@ pathtrace_match(struct tcb *tcp) s->sys_func == sys_epoll_create || s->sys_func == sys_socket || s->sys_func == sys_socketpair || - strcmp(s->sys_name, "fanotify_init") == 0) + s->sys_func == sys_fanotify_init) { /* * These have TRACE_FILE or TRACE_DESCRIPTOR or TRACE_NETWORK set, |