[PATCH v3 4/6] Improve fd filtering
Nikolay Marchuk
marchuk.nikolay.a at gmail.com
Thu Jun 29 07:46:13 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 false;
+ }
+ } else {
+ unsigned int n;
+
+ if (umove(tcp, tcp->u_arg[0], &oldselect_args)) {
+ return false;
+ }
+
+ 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 false;
+ /* 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 false;
+
+ 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