diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-01-24 19:28:36 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-01-27 17:08:43 +0100 |
| commit | 08146b1a84f975e2cc1007242b4202dc5cc0e5c5 (patch) | |
| tree | ad9f57cfbed4b9008223359d0f765a2b6a27a209 /executor | |
| parent | 5d7477249ba074bbdc9ffbf80314397dbe90e886 (diff) | |
sys/linux: extend netfilter descriptions
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common_linux.h | 154 | ||||
| -rw-r--r-- | executor/executor_linux.cc | 4 | ||||
| -rw-r--r-- | executor/syscalls_linux.h | 25 |
3 files changed, 172 insertions, 11 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h index c971801fe..30a5a0c49 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -71,6 +71,11 @@ #include <sys/stat.h> #include <sys/uio.h> #endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE) +#include <linux/net.h> +#include <netinet/in.h> +#include <sys/socket.h> +#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) #include <errno.h> #include <fcntl.h> @@ -947,6 +952,149 @@ static int do_sandbox_namespace(int executor_pid, bool enable_tun) } #endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE) +// checkpoint/reset_net_namespace partially resets net namespace to initial state +// after each test. Currently it resets only ipv4 netfilter state. +// Ideally, we just create a new net namespace for each test, +// however it's too slow (1-1.5 seconds per namespace, not parallelizable). + +// Linux headers do not compile for C++, so we have to define the structs manualy. +struct ipt_getinfo { + char name[32]; + unsigned int valid_hooks; + unsigned int hook_entry[5]; + unsigned int underflow[5]; + unsigned int num_entries; + unsigned int size; +}; + +struct ipt_get_entries { + char name[32]; + unsigned int size; + unsigned int pad; + char entrytable[1024]; +}; + +struct xt_counters { + uint64 pcnt, bcnt; +}; + +struct ipt_replace { + char name[32]; + unsigned int valid_hooks; + unsigned int num_entries; + unsigned int size; + unsigned int hook_entry[5]; + unsigned int underflow[5]; + unsigned int num_counters; + struct xt_counters* counters; + char entrytable[1024]; +}; + +struct ipt_table_desc { + const char* name; + struct ipt_getinfo info; + struct ipt_get_entries entries; + struct ipt_replace replace; + struct xt_counters counters[10]; +}; + +static struct ipt_table_desc ipv4_tables[] = { + {.name = "filter"}, + {.name = "nat"}, + {.name = "mangle"}, + {.name = "raw"}, + {.name = "security"}, +}; + +#define IPT_BASE_CTL 64 +#define IPT_SO_SET_REPLACE (IPT_BASE_CTL) +#define IPT_SO_GET_INFO (IPT_BASE_CTL) +#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1) + +static void checkpoint_net_namespace(void) +{ + socklen_t optlen; + unsigned i; + int fd; + + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd == -1) + fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)"); + for (i = 0; i < sizeof(ipv4_tables) / sizeof(ipv4_tables[0]); i++) { + struct ipt_table_desc* table = &ipv4_tables[i]; + strcpy(table->info.name, table->name); + strcpy(table->entries.name, table->name); + strcpy(table->replace.name, table->name); + optlen = sizeof(table->info); + if (getsockopt(fd, SOL_IP, IPT_SO_GET_INFO, &table->info, &optlen)) { + switch (errno) { + case EPERM: + case ENOENT: + case ENOPROTOOPT: + continue; + } + fail("getsockopt(IPT_SO_GET_INFO)"); + } + if (table->info.size > sizeof(table->entries.entrytable)) + fail("table size is too large: %u", table->info.size); + if (table->info.num_entries > sizeof(table->counters) / sizeof(table->counters[0])) + fail("too many counters: %u", table->info.num_entries); + table->entries.size = table->info.size; + optlen = sizeof(table->entries) - sizeof(table->entries.entrytable) + table->info.size; + if (getsockopt(fd, SOL_IP, IPT_SO_GET_ENTRIES, &table->entries, &optlen)) + fail("getsockopt(IPT_SO_GET_ENTRIES)"); + table->replace.valid_hooks = table->info.valid_hooks; + table->replace.num_entries = table->info.num_entries; + table->replace.counters = table->counters; + table->replace.size = table->info.size; + memcpy(table->replace.hook_entry, table->info.hook_entry, sizeof(table->replace.hook_entry)); + memcpy(table->replace.underflow, table->info.underflow, sizeof(table->replace.underflow)); + memcpy(table->replace.entrytable, table->entries.entrytable, table->info.size); + } + close(fd); +} + +static void reset_net_namespace(void) +{ + struct ipt_get_entries entries; + struct ipt_getinfo info; + socklen_t optlen; + unsigned i; + int fd; + + memset(&info, 0, sizeof(info)); + memset(&entries, 0, sizeof(entries)); + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd == -1) + fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)"); + for (i = 0; i < sizeof(ipv4_tables) / sizeof(ipv4_tables[0]); i++) { + struct ipt_table_desc* table = &ipv4_tables[i]; + if (table->info.valid_hooks == 0) + continue; + strcpy(info.name, table->name); + optlen = sizeof(info); + if (getsockopt(fd, SOL_IP, IPT_SO_GET_INFO, &info, &optlen)) + fail("getsockopt(IPT_SO_GET_INFO)"); + if (memcmp(&table->info, &info, sizeof(table->info)) == 0) { + strcpy(entries.name, table->name); + entries.size = table->info.size; + optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size; + if (getsockopt(fd, SOL_IP, IPT_SO_GET_ENTRIES, &entries, &optlen)) + fail("getsockopt(IPT_SO_GET_ENTRIES)"); + if (memcmp(&table->entries, &entries, optlen) == 0) + continue; + } + debug("resetting iptable %s\n", table->name); + table->replace.num_counters = info.num_entries; + optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size; + if (setsockopt(fd, SOL_IP, IPT_SO_SET_REPLACE, &table->replace, optlen)) + fail("setsockopt(IPT_SO_SET_REPLACE)"); + } + close(fd); +} +#endif + #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) // One does not simply remove a directory. // There can be mounts, so we need to try to umount. @@ -1068,6 +1216,9 @@ static void test(); void loop() { int iter; +#if defined(SYZ_RESET_NET_NAMESPACE) + checkpoint_net_namespace(); +#endif for (iter = 0;; iter++) { #ifdef SYZ_USE_TMP_DIR char cwdbuf[256]; @@ -1109,6 +1260,9 @@ void loop() #ifdef SYZ_USE_TMP_DIR remove_dir(cwdbuf); #endif +#if defined(SYZ_RESET_NET_NAMESPACE) + reset_net_namespace(); +#endif } } #else diff --git a/executor/executor_linux.cc b/executor/executor_linux.cc index 9511f1d57..8fec5ac6d 100644 --- a/executor/executor_linux.cc +++ b/executor/executor_linux.cc @@ -119,6 +119,7 @@ void loop() { // Tell parent that we are ready to serve. reply_handshake(); + checkpoint_net_namespace(); for (int iter = 0;; iter++) { // Create a new private work dir for this test (removed at the end of the loop). @@ -205,8 +206,9 @@ void loop() fail("child failed"); if (status == kErrorStatus) error("child errored"); - remove_dir(cwdbuf); reply_execute(0); + remove_dir(cwdbuf); + reset_net_namespace(); } } diff --git a/executor/syscalls_linux.h b/executor/syscalls_linux.h index c7df2929d..3e8e70386 100644 --- a/executor/syscalls_linux.h +++ b/executor/syscalls_linux.h @@ -2,8 +2,8 @@ #if defined(__i386__) || 0 #define GOARCH "386" -#define SYZ_REVISION "e40ab07d179f415c45cf2ecb376828bda26f4141" -unsigned syscall_count = 1575; +#define SYZ_REVISION "a721e2aa93c1691bcd8e5cc8fa24a913235f2483" +unsigned syscall_count = 1576; call_t syscalls[] = { {"accept4", 364}, {"accept4$alg", 364}, @@ -1194,6 +1194,7 @@ call_t syscalls[] = { {"setsockopt", 366}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 366}, {"setsockopt$ALG_SET_KEY", 366}, + {"setsockopt$IP6T_SO_SET_REPLACE", 366}, {"setsockopt$IPT_SO_SET_REPLACE", 366}, {"setsockopt$RDS_CANCEL_SENT_TO", 366}, {"setsockopt$RDS_CONG_MONITOR", 366}, @@ -1586,8 +1587,8 @@ call_t syscalls[] = { #if defined(__x86_64__) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "94bcfe970dc4e9b561898e0fac423f4472ebae6a" -unsigned syscall_count = 1628; +#define SYZ_REVISION "bc125788702a194b20b8cd6fbe0891f5129b9246" +unsigned syscall_count = 1629; call_t syscalls[] = { {"accept", 43}, {"accept$alg", 43}, @@ -2819,6 +2820,7 @@ call_t syscalls[] = { {"setsockopt", 54}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 54}, {"setsockopt$ALG_SET_KEY", 54}, + {"setsockopt$IP6T_SO_SET_REPLACE", 54}, {"setsockopt$IPT_SO_SET_REPLACE", 54}, {"setsockopt$RDS_CANCEL_SENT_TO", 54}, {"setsockopt$RDS_CONG_MONITOR", 54}, @@ -3223,8 +3225,8 @@ call_t syscalls[] = { #if defined(__arm__) || 0 #define GOARCH "arm" -#define SYZ_REVISION "ede3e4008d609f29bd0f3b8347254e4b85aef2a4" -unsigned syscall_count = 1585; +#define SYZ_REVISION "30d6c04729a43d9c1a297cd46ae6ecea4bbd2828" +unsigned syscall_count = 1586; call_t syscalls[] = { {"accept", 285}, {"accept$alg", 285}, @@ -4416,6 +4418,7 @@ call_t syscalls[] = { {"setsockopt", 294}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 294}, {"setsockopt$ALG_SET_KEY", 294}, + {"setsockopt$IP6T_SO_SET_REPLACE", 294}, {"setsockopt$IPT_SO_SET_REPLACE", 294}, {"setsockopt$RDS_CANCEL_SENT_TO", 294}, {"setsockopt$RDS_CONG_MONITOR", 294}, @@ -4817,8 +4820,8 @@ call_t syscalls[] = { #if defined(__aarch64__) || 0 #define GOARCH "arm64" -#define SYZ_REVISION "42b28c68ad2166ea4c3543065f25bf48d8c40d64" -unsigned syscall_count = 1557; +#define SYZ_REVISION "3665ee48a0043014f610083086fb5983216220fa" +unsigned syscall_count = 1558; call_t syscalls[] = { {"accept", 202}, {"accept$alg", 202}, @@ -5991,6 +5994,7 @@ call_t syscalls[] = { {"setsockopt", 208}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 208}, {"setsockopt$ALG_SET_KEY", 208}, + {"setsockopt$IP6T_SO_SET_REPLACE", 208}, {"setsockopt$IPT_SO_SET_REPLACE", 208}, {"setsockopt$RDS_CANCEL_SENT_TO", 208}, {"setsockopt$RDS_CONG_MONITOR", 208}, @@ -6383,8 +6387,8 @@ call_t syscalls[] = { #if defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || 0 #define GOARCH "ppc64le" -#define SYZ_REVISION "442772ac6b8522876e25582e1d1d0e4dd1c1f371" -unsigned syscall_count = 1544; +#define SYZ_REVISION "d14f1cf09eff5bf9a0ba0c62ea72dadb8fa07165" +unsigned syscall_count = 1545; call_t syscalls[] = { {"accept", 330}, {"accept$alg", 330}, @@ -7545,6 +7549,7 @@ call_t syscalls[] = { {"setsockopt", 339}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 339}, {"setsockopt$ALG_SET_KEY", 339}, + {"setsockopt$IP6T_SO_SET_REPLACE", 339}, {"setsockopt$IPT_SO_SET_REPLACE", 339}, {"setsockopt$RDS_CANCEL_SENT_TO", 339}, {"setsockopt$RDS_CONG_MONITOR", 339}, |
