[PATCH v2 4/6] Improve fd filtering

Nikolay Marchuk marchuk.nikolay.a at gmail.com
Tue Jun 27 07:48:46 UTC 2017


* basic_actions (apply_read, apply_write): Add syscall check.
* basic_filters (run_fd_filter): Implement more accurate fd filtering.
* defs.h (read_dumped, write_dumped): Add new flag checking macroses.
* syscall.c (dumpio): And use them.
---
 basic_actions.c |  30 ++++++++++-
 basic_filters.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 defs.h          |   2 +
 syscall.c       |   4 +-
 4 files changed, 191 insertions(+), 8 deletions(-)

diff --git a/basic_actions.c b/basic_actions.c
index 1eb597e..bd05832 100644
--- a/basic_actions.c
+++ b/basic_actions.c
@@ -26,6 +26,7 @@
  */
 #include "defs.h"
 #include "filter.h"
+#include "syscall.h"
 
 bool
 is_traced(struct tcb *tcp)
@@ -131,13 +132,38 @@ void free_inject(void *_priv_data)
 void
 apply_read(struct tcb *tcp, void *_priv_data)
 {
-	tcp->qual_flg |= QUAL_READ;
+	switch (tcp->s_ent->sen) {
+	case SEN_read:
+	case SEN_pread:
+	case SEN_recv:
+	case SEN_recvfrom:
+	case SEN_mq_timedreceive:
+	case SEN_readv:
+	case SEN_preadv:
+	case SEN_preadv2:
+	case SEN_recvmsg:
+	case SEN_recvmmsg:
+		tcp->qual_flg |= QUAL_READ;
+	}
 }
 
 void
 apply_write(struct tcb *tcp, void *_priv_data)
 {
-	tcp->qual_flg |= QUAL_WRITE;
+	switch (tcp->s_ent->sen) {
+	case SEN_write:
+	case SEN_pwrite:
+	case SEN_send:
+	case SEN_sendto:
+	case SEN_mq_timedsend:
+	case SEN_writev:
+	case SEN_pwritev:
+	case SEN_pwritev2:
+	case SEN_vmsplice:
+	case SEN_sendmsg:
+	case SEN_sendmmsg:
+		tcp->qual_flg |= QUAL_WRITE;
+	}
 }
 
 void
diff --git a/basic_filters.c b/basic_filters.c
index d0816a4..82f1656 100644
--- a/basic_filters.c
+++ b/basic_filters.c
@@ -27,6 +27,8 @@
  */
 #include "defs.h"
 #include <regex.h>
+#include <poll.h>
+#include "syscall.h"
 
 typedef unsigned int number_slot_t;
 #define BITS_PER_SLOT (sizeof(number_slot_t) * 8)
@@ -412,14 +414,167 @@ parse_fd_filter(const char *str, const char *const name)
 	return set;
 }
 
+static bool
+is_fd_in_set(int fd, struct number_set *set) {
+	if (fd < 0)
+		return false;
+	return is_number_in_set(fd, set);
+}
+
 bool
 run_fd_filter(struct tcb *tcp, void *_priv_data)
 {
-	int fd = tcp->u_arg[0];
-	if (fd < 0)
-		return false;
 	struct number_set *set = (struct number_set *)_priv_data;
-	return is_number_in_set(fd, set);
+	const struct_sysent *s_ent = tcp->s_ent;
+	/*
+	 * mq_timedsend and mq_timedreceive are not marked as descriptor
+	 * syscalls, but they can be dumped with -e read/write.
+	*/
+	switch (s_ent->sen) {
+	case SEN_mq_timedsend:
+	case SEN_mq_timedreceive:
+		return is_fd_in_set(tcp->u_arg[0], set);
+	}
+	if (!(s_ent->sys_flags & (TRACE_DESC | TRACE_NETWORK)))
+		return false;
+	switch (s_ent->sen) {
+	case SEN_dup2:
+	case SEN_dup3:
+	case SEN_kexec_file_load:
+	case SEN_sendfile:
+	case SEN_sendfile64:
+	case SEN_tee:
+		return is_fd_in_set(tcp->u_arg[0], set)
+		       || is_fd_in_set(tcp->u_arg[1], set);
+	case SEN_linkat:
+	case SEN_renameat2:
+	case SEN_renameat:
+	case SEN_copy_file_range:
+	case SEN_splice:
+		return is_fd_in_set(tcp->u_arg[0], set)
+		       || is_fd_in_set(tcp->u_arg[2], set);
+
+	case SEN_old_mmap:
+#if defined(S390)
+	case SEN_old_mmap_pgoff:
+#endif
+	case SEN_mmap:
+	case SEN_mmap_4koff:
+	case SEN_mmap_pgoff:
+	case SEN_ARCH_mmap:
+		return is_fd_in_set(tcp->u_arg[4], set);
+	case SEN_symlinkat:
+		return is_fd_in_set(tcp->u_arg[1], set);
+	case SEN_epoll_ctl:
+		return is_fd_in_set(tcp->u_arg[2], set);
+	case SEN_fanotify_mark:
+		return is_fd_in_set(tcp->u_arg[3], set);
+	case SEN_oldselect:
+	case SEN_pselect6:
+	case SEN_select:
+	{
+		int     i, j;
+		int     nfds;
+		kernel_ulong_t *args;
+		kernel_ulong_t select_args[5];
+		unsigned int oldselect_args[5];
+		unsigned int fdsize;
+		fd_set *fds;
+
+		if (SEN_oldselect == s_ent->sen) {
+			if (sizeof(*select_args) == sizeof(*oldselect_args)) {
+				if (umove(tcp, tcp->u_arg[0], &select_args)) {
+					return 0;
+				}
+			} else {
+				unsigned int n;
+
+				if (umove(tcp, tcp->u_arg[0], &oldselect_args)) {
+					return 0;
+				}
+
+				for (n = 0; n < 5; ++n) {
+					select_args[n] = oldselect_args[n];
+				}
+			}
+			args = select_args;
+		} else {
+			args = tcp->u_arg;
+		}
+
+		/* Kernel truncates arg[0] to int, we do the same. */
+		nfds = (int) args[0];
+		/* Kernel rejects negative nfds, so we don't parse it either. */
+		if (nfds <= 0)
+			return 0;
+		/* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
+		if (nfds > 1024*1024)
+			nfds = 1024*1024;
+		fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
+		fds = xmalloc(fdsize);
+
+		for (i = 1; i <= 3; ++i) {
+			if (args[i] == 0)
+				continue;
+			if (umoven(tcp, args[i], fdsize, fds) < 0) {
+				continue;
+			}
+			for (j = 0;; j++) {
+				j = next_set_bit(fds, j, nfds);
+				if (j < 0)
+					break;
+				if (is_fd_in_set(j, set)) {
+					free(fds);
+					return true;
+				}
+			}
+		}
+		free(fds);
+		return false;
+	}
+	case SEN_poll:
+	case SEN_ppoll:
+	{
+		struct pollfd fds;
+		unsigned nfds;
+		kernel_ulong_t start, cur, end;
+
+		start = tcp->u_arg[0];
+		nfds = tcp->u_arg[1];
+
+		end = start + sizeof(fds) * nfds;
+
+		if (nfds == 0 || end < start)
+			return 0;
+
+		for (cur = start; cur < end; cur += sizeof(fds))
+			if ((umove(tcp, cur, &fds) == 0)
+			    && is_fd_in_set(fds.fd, set))
+				return true;
+
+		return false;
+	}
+	case SEN_bpf:
+	case SEN_creat:
+	case SEN_epoll_create:
+	case SEN_epoll_create1:
+	case SEN_eventfd2:
+	case SEN_eventfd:
+	case SEN_fanotify_init:
+	case SEN_inotify_init1:
+	case SEN_memfd_create:
+	case SEN_open:
+	case SEN_perf_event_open:
+	case SEN_pipe:
+	case SEN_pipe2:
+	case SEN_printargs:
+	case SEN_socket:
+	case SEN_socketpair:
+	case SEN_timerfd_create:
+	case SEN_userfaultfd:
+		return false;
+	}
+	return is_fd_in_set(tcp->u_arg[0], set);
 }
 
 void
diff --git a/defs.h b/defs.h
index 21dec65..4b3516b 100644
--- a/defs.h
+++ b/defs.h
@@ -283,6 +283,8 @@ struct tcb {
 #define syserror(tcp)	((tcp)->u_error != 0)
 #define verbose(tcp)	((tcp)->qual_flg & QUAL_VERBOSE)
 #define abbrev(tcp)	((tcp)->qual_flg & QUAL_ABBREV)
+#define read_dumped(tcp)	((tcp)->qual_flg & QUAL_READ)
+#define write_dumped(tcp)	((tcp)->qual_flg & QUAL_WRITE)
 #define filtered(tcp)	((tcp)->flags & TCB_FILTERED)
 #define hide_log(tcp)	((tcp)->flags & TCB_HIDE_LOG)
 
diff --git a/syscall.c b/syscall.c
index b6e1ba3..c782f99 100644
--- a/syscall.c
+++ b/syscall.c
@@ -465,7 +465,7 @@ dumpio(struct tcb *tcp)
 	if (fd < 0)
 		return;
 
-	if (tcp->qual_flg & QUAL_READ) {
+	if (read_dumped(tcp)) {
 		switch (tcp->s_ent->sen) {
 		case SEN_read:
 		case SEN_pread:
@@ -488,7 +488,7 @@ dumpio(struct tcb *tcp)
 			return;
 		}
 	}
-	if (tcp->qual_flg & QUAL_WRITE) {
+	if (write_dumped(tcp)) {
 		switch (tcp->s_ent->sen) {
 		case SEN_write:
 		case SEN_pwrite:
-- 
2.1.4





More information about the Strace-devel mailing list