From 033b610ec91096a5791c90761df1289fd33280e6 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 29 Jan 2018 13:44:57 +0100 Subject: sys/linux: improve netfilter descriptions Put the underflow entry at the end. Entries must end on an unconditional, non-goto entry, otherwise fallthrough from the last entry is invalid. Add arp tables support. Split unspec matches/targets to unspec and inet. Reset ipv6 and arp tables in executor. Fix number of counters in tables. Plus a bunch of assorted fixes for matches/targets. --- executor/common_linux.h | 230 ++++++++++++++++++++++++++++++++++++++-------- executor/syscalls_linux.h | 28 ++++-- 2 files changed, 211 insertions(+), 47 deletions(-) (limited to 'executor') diff --git a/executor/common_linux.h b/executor/common_linux.h index d636c85f9..729cdcba0 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -959,6 +959,13 @@ static int do_sandbox_namespace(int executor_pid, bool enable_tun) // 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. +#define XT_TABLE_SIZE 1536 +#define XT_MAX_ENTRIES 10 + +struct xt_counters { + uint64 pcnt, bcnt; +}; + struct ipt_getinfo { char name[32]; unsigned int valid_hooks; @@ -971,11 +978,7 @@ struct ipt_getinfo { struct ipt_get_entries { char name[32]; unsigned int size; - void* entrytable[1024 / sizeof(void*)]; -}; - -struct xt_counters { - uint64 pcnt, bcnt; + void* entrytable[XT_TABLE_SIZE / sizeof(void*)]; }; struct ipt_replace { @@ -987,15 +990,13 @@ struct ipt_replace { unsigned int underflow[5]; unsigned int num_counters; struct xt_counters* counters; - char entrytable[1024]; + char entrytable[XT_TABLE_SIZE]; }; 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[] = { @@ -1006,27 +1007,76 @@ static struct ipt_table_desc ipv4_tables[] = { {.name = "security"}, }; +static struct ipt_table_desc ipv6_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) +struct arpt_getinfo { + char name[32]; + unsigned int valid_hooks; + unsigned int hook_entry[3]; + unsigned int underflow[3]; + unsigned int num_entries; + unsigned int size; +}; + +struct arpt_get_entries { + char name[32]; + unsigned int size; + void* entrytable[XT_TABLE_SIZE / sizeof(void*)]; +}; + +struct arpt_replace { + char name[32]; + unsigned int valid_hooks; + unsigned int num_entries; + unsigned int size; + unsigned int hook_entry[3]; + unsigned int underflow[3]; + unsigned int num_counters; + struct xt_counters* counters; + char entrytable[XT_TABLE_SIZE]; +}; + +struct arpt_table_desc { + const char* name; + struct arpt_getinfo info; + struct arpt_replace replace; +}; + +static struct arpt_table_desc arpt_tables[] = { + {.name = "filter"}, +}; + +#define ARPT_BASE_CTL 96 +#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL) +#define ARPT_SO_GET_INFO (ARPT_BASE_CTL) +#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1) + +static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables, int family, int level) { + struct ipt_get_entries entries; socklen_t optlen; - unsigned i; - int fd; + int fd, i; - fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + fd = socket(family, 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]; + fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family); + for (i = 0; i < num_tables; i++) { + struct ipt_table_desc* table = &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)) { + if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) { switch (errno) { case EPERM: case ENOENT: @@ -1035,63 +1085,169 @@ static void checkpoint_net_namespace(void) } fail("getsockopt(IPT_SO_GET_INFO)"); } - if (table->info.size > sizeof(table->entries.entrytable)) + debug("checkpoint iptable %s/%d: entries=%d hooks=%x size=%d\n", + table->name, family, table->info.num_entries, table->info.valid_hooks, + table->info.size); + if (table->info.size > sizeof(table->replace.entrytable)) fail("table size is too large: %u", table->info.size); - if (table->info.num_entries > sizeof(table->counters) / sizeof(table->counters[0])) + if (table->info.num_entries > XT_MAX_ENTRIES) 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)) + memset(&entries, 0, sizeof(entries)); + strcpy(entries.name, table->name); + entries.size = table->info.size; + optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size; + if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &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); + memcpy(table->replace.entrytable, entries.entrytable, table->info.size); } close(fd); } -static void reset_net_namespace(void) +static void reset_iptables(struct ipt_table_desc* tables, int num_tables, int family, int level) { + struct xt_counters counters[XT_MAX_ENTRIES]; struct ipt_get_entries entries; struct ipt_getinfo info; socklen_t optlen; - unsigned i; - int fd; + int fd, i; - memset(&info, 0, sizeof(info)); - memset(&entries, 0, sizeof(entries)); - fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + fd = socket(family, 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]; + fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family); + for (i = 0; i < num_tables; i++) { + struct ipt_table_desc* table = &tables[i]; if (table->info.valid_hooks == 0) continue; + memset(&info, 0, sizeof(info)); strcpy(info.name, table->name); optlen = sizeof(info); - if (getsockopt(fd, SOL_IP, IPT_SO_GET_INFO, &info, &optlen)) + if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen)) fail("getsockopt(IPT_SO_GET_INFO)"); if (memcmp(&table->info, &info, sizeof(table->info)) == 0) { + memset(&entries, 0, sizeof(entries)); 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)) + if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen)) fail("getsockopt(IPT_SO_GET_ENTRIES)"); - if (memcmp(&table->entries, &entries, optlen) == 0) + if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0) continue; } debug("resetting iptable %s\n", table->name); table->replace.num_counters = info.num_entries; + table->replace.counters = counters; optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size; - if (setsockopt(fd, SOL_IP, IPT_SO_SET_REPLACE, &table->replace, optlen)) + if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen)) fail("setsockopt(IPT_SO_SET_REPLACE)"); } close(fd); } + +static void checkpoint_arptables(void) +{ + struct arpt_get_entries entries; + 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(arpt_tables) / sizeof(arpt_tables[0]); i++) { + struct arpt_table_desc* table = &arpt_tables[i]; + strcpy(table->info.name, table->name); + strcpy(table->replace.name, table->name); + optlen = sizeof(table->info); + if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) { + switch (errno) { + case EPERM: + case ENOENT: + case ENOPROTOOPT: + continue; + } + fail("getsockopt(ARPT_SO_GET_INFO)"); + } + debug("checkpoint arptable %s: entries=%d hooks=%x size=%d\n", + table->name, table->info.num_entries, table->info.valid_hooks, table->info.size); + if (table->info.size > sizeof(table->replace.entrytable)) + fail("table size is too large: %u", table->info.size); + if (table->info.num_entries > XT_MAX_ENTRIES) + fail("too many counters: %u", table->info.num_entries); + memset(&entries, 0, sizeof(entries)); + strcpy(entries.name, table->name); + entries.size = table->info.size; + optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size; + if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen)) + fail("getsockopt(ARPT_SO_GET_ENTRIES)"); + table->replace.valid_hooks = table->info.valid_hooks; + table->replace.num_entries = table->info.num_entries; + 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, entries.entrytable, table->info.size); + } + close(fd); +} + +static void reset_arptables() +{ + struct xt_counters counters[XT_MAX_ENTRIES]; + struct arpt_get_entries entries; + struct arpt_getinfo info; + 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(arpt_tables) / sizeof(arpt_tables[0]); i++) { + struct arpt_table_desc* table = &arpt_tables[i]; + if (table->info.valid_hooks == 0) + continue; + memset(&info, 0, sizeof(info)); + strcpy(info.name, table->name); + optlen = sizeof(info); + if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen)) + fail("getsockopt(ARPT_SO_GET_INFO)"); + if (memcmp(&table->info, &info, sizeof(table->info)) == 0) { + memset(&entries, 0, sizeof(entries)); + strcpy(entries.name, table->name); + entries.size = table->info.size; + optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size; + if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen)) + fail("getsockopt(ARPT_SO_GET_ENTRIES)"); + if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0) + continue; + } + debug("resetting arptable %s\n", table->name); + table->replace.num_counters = info.num_entries; + table->replace.counters = counters; + optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size; + if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen)) + fail("setsockopt(ARPT_SO_SET_REPLACE)"); + } + close(fd); +} + +static void checkpoint_net_namespace(void) +{ + checkpoint_arptables(); + checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP); + checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6); +} + +static void reset_net_namespace(void) +{ + reset_arptables(); + reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP); + reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6); +} #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) diff --git a/executor/syscalls_linux.h b/executor/syscalls_linux.h index b4e9c6617..24b7f677c 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 "47ec3cf48f6c1c8a279acf0ac6752173b5a2d6c1" -unsigned syscall_count = 1581; +#define SYZ_REVISION "67eb9eadac89980dc20b01fc8861359a1bb38c63" +unsigned syscall_count = 1582; call_t syscalls[] = { {"accept4", 364}, {"accept4$alg", 364}, @@ -1199,6 +1199,7 @@ call_t syscalls[] = { {"setsockopt", 366}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 366}, {"setsockopt$ALG_SET_KEY", 366}, + {"setsockopt$ARPT_SO_SET_REPLACE", 366}, {"setsockopt$IP6T_SO_SET_REPLACE", 366}, {"setsockopt$IPT_SO_SET_REPLACE", 366}, {"setsockopt$RDS_CANCEL_SENT_TO", 366}, @@ -1592,8 +1593,8 @@ call_t syscalls[] = { #if defined(__x86_64__) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "cbf77bff7fbf168a36293cc240e1fd599718aae4" -unsigned syscall_count = 1634; +#define SYZ_REVISION "a71eb1f658a04d8e2dec810cc23df01f68770093" +unsigned syscall_count = 1635; call_t syscalls[] = { {"accept", 43}, {"accept$alg", 43}, @@ -2830,6 +2831,7 @@ call_t syscalls[] = { {"setsockopt", 54}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 54}, {"setsockopt$ALG_SET_KEY", 54}, + {"setsockopt$ARPT_SO_SET_REPLACE", 54}, {"setsockopt$IP6T_SO_SET_REPLACE", 54}, {"setsockopt$IPT_SO_SET_REPLACE", 54}, {"setsockopt$RDS_CANCEL_SENT_TO", 54}, @@ -3235,8 +3237,8 @@ call_t syscalls[] = { #if defined(__arm__) || 0 #define GOARCH "arm" -#define SYZ_REVISION "2bcd2d52a7f0e89565375875e7487c79257c1b8d" -unsigned syscall_count = 1591; +#define SYZ_REVISION "d5c13287ed0c6e02f77bfe251b77852a2dba43c0" +unsigned syscall_count = 1592; call_t syscalls[] = { {"accept", 285}, {"accept$alg", 285}, @@ -4433,6 +4435,7 @@ call_t syscalls[] = { {"setsockopt", 294}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 294}, {"setsockopt$ALG_SET_KEY", 294}, + {"setsockopt$ARPT_SO_SET_REPLACE", 294}, {"setsockopt$IP6T_SO_SET_REPLACE", 294}, {"setsockopt$IPT_SO_SET_REPLACE", 294}, {"setsockopt$RDS_CANCEL_SENT_TO", 294}, @@ -4835,8 +4838,8 @@ call_t syscalls[] = { #if defined(__aarch64__) || 0 #define GOARCH "arm64" -#define SYZ_REVISION "de8c14c28805b67f66696e7afa155ea7e8243cbf" -unsigned syscall_count = 1563; +#define SYZ_REVISION "3259e2eab38706f39ed08f998834cded740681ab" +unsigned syscall_count = 1564; call_t syscalls[] = { {"accept", 202}, {"accept$alg", 202}, @@ -6014,6 +6017,7 @@ call_t syscalls[] = { {"setsockopt", 208}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 208}, {"setsockopt$ALG_SET_KEY", 208}, + {"setsockopt$ARPT_SO_SET_REPLACE", 208}, {"setsockopt$IP6T_SO_SET_REPLACE", 208}, {"setsockopt$IPT_SO_SET_REPLACE", 208}, {"setsockopt$RDS_CANCEL_SENT_TO", 208}, @@ -6407,8 +6411,8 @@ call_t syscalls[] = { #if defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || 0 #define GOARCH "ppc64le" -#define SYZ_REVISION "22e496aa45301c44268e52fce477f4dc1ee30157" -unsigned syscall_count = 1550; +#define SYZ_REVISION "d76549b3801a4d21411b03ca98e3bbd2176ee5dd" +unsigned syscall_count = 1554; call_t syscalls[] = { {"accept", 330}, {"accept$alg", 330}, @@ -7441,6 +7445,9 @@ call_t syscalls[] = { {"pipe", 42}, {"pipe2", 317}, {"pivot_root", 203}, + {"pkey_alloc", 384}, + {"pkey_free", 385}, + {"pkey_mprotect", 386}, {"poll", 167}, {"ppoll", 281}, {"prctl$getname", 171}, @@ -7574,6 +7581,7 @@ call_t syscalls[] = { {"setsockopt", 339}, {"setsockopt$ALG_SET_AEAD_AUTHSIZE", 339}, {"setsockopt$ALG_SET_KEY", 339}, + {"setsockopt$ARPT_SO_SET_REPLACE", 339}, {"setsockopt$IP6T_SO_SET_REPLACE", 339}, {"setsockopt$IPT_SO_SET_REPLACE", 339}, {"setsockopt$RDS_CANCEL_SENT_TO", 339}, -- cgit mrf-deployment