diff options
| author | Andrey Konovalov <andreyknvl@gmail.com> | 2017-05-26 15:28:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-05-26 15:28:57 +0200 |
| commit | 8320ea0056ddf1f35ea1daf9584f9f9aa6ae4491 (patch) | |
| tree | 267621aa41026391e91003045cfe3bbec562993d /executor | |
| parent | a2ef63b51f2efd9213f410577d07dead25a0f85f (diff) | |
| parent | f919224c44b9828208a3cce79b93183df8ca4fb4 (diff) | |
Merge pull request #175 from xairy/up-tcp-sequence
sys, executor: extract tcp sequence numbers from /dev/net/tun
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common.h | 152 | ||||
| -rw-r--r-- | executor/executor.cc | 5 |
2 files changed, 146 insertions, 11 deletions
diff --git a/executor/common.h b/executor/common.h index c264d7b70..c32341f57 100644 --- a/executor/common.h +++ b/executor/common.h @@ -20,10 +20,15 @@ #include <sys/wait.h> #include <linux/capability.h> -#include <linux/if.h> -#include <linux/if_tun.h> #include <linux/kvm.h> #include <linux/sched.h> + +#include <arpa/inet.h> +#include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/if_tun.h> +#include <linux/ip.h> +#include <linux/tcp.h> #include <net/if_arp.h> #include <assert.h> @@ -184,7 +189,11 @@ static void install_segv_handler() *(type*)(addr) = new_val; \ } -#ifdef __NR_syz_emit_ethernet +#if defined(__NR_syz_emit_ethernet) || defined(__NR_syz_extract_tcp_res) +#define SYZ_TUN_ENABLE +#endif + +#ifdef SYZ_TUN_ENABLE static void vsnprintf_check(char* str, size_t size, const char* format, va_list args) { int rv; @@ -225,6 +234,8 @@ static void execute_command(const char* format, ...) int tunfd = -1; +#define SYZ_TUN_MAX_PACKET_SIZE (64 << 10) + // sysgen knowns about this constant (maxPids) #define MAX_PIDS 32 #define ADDR_MAX_LEN 32 @@ -235,8 +246,8 @@ int tunfd = -1; #define LOCAL_IPV4 "172.20.%d.170" #define REMOTE_IPV4 "172.20.%d.187" -#define LOCAL_IPV6 "fd00::%02hxaa" -#define REMOTE_IPV6 "fd00::%02hxbb" +#define LOCAL_IPV6 "fe80::%02hxaa" +#define REMOTE_IPV6 "fe80::%02hxbb" static void initialize_tun(uint64_t pid) { @@ -244,7 +255,7 @@ static void initialize_tun(uint64_t pid) fail("tun: no more than %d executors", MAX_PIDS); int id = pid; - tunfd = open("/dev/net/tun", O_RDWR); + tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK); if (tunfd == -1) fail("tun: can't open /dev/net/tun"); @@ -273,12 +284,19 @@ static void initialize_tun(uint64_t pid) char remote_ipv6[ADDR_MAX_LEN]; snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, id); + // Disable IPv6 DAD, otherwise the address remains unusable until DAD completes. + execute_command("sysctl -w net.ipv6.conf.%s.accept_dad=0", iface); + + // Disable IPv6 router solicitation to prevent IPv6 spam. + execute_command("sysctl -w net.ipv6.conf.%s.router_solicitations=0", iface); + // There seems to be no way to disable IPv6 MTD to prevent more IPv6 spam. + execute_command("ip link set dev %s address %s", iface, local_mac); execute_command("ip addr add %s/24 dev %s", local_ipv4, iface); execute_command("ip -6 addr add %s/120 dev %s", local_ipv6, iface); execute_command("ip neigh add %s lladdr %s dev %s nud permanent", remote_ipv4, remote_mac, iface); execute_command("ip -6 neigh add %s lladdr %s dev %s nud permanent", remote_ipv6, remote_mac, iface); - execute_command("ip link set %s up", iface); + execute_command("ip link set dev %s up", iface); } static void setup_tun(uint64_t pid, bool enable_tun) @@ -287,16 +305,124 @@ static void setup_tun(uint64_t pid, bool enable_tun) initialize_tun(pid); } +void debug_dump_data(const char* data, int length) +{ + int i; + for (i = 0; i < length; i++) { + debug("%02hx ", (uint8_t)data[i] & (uint8_t)0xff); + if (i % 16 == 15) + debug("\n"); + } + if (i % 16 != 0) + debug("\n"); +} +#endif // SYZ_TUN_ENABLE + +#ifdef __NR_syz_emit_ethernet static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1) { + // syz_emit_ethernet(len len[packet], packet ptr[in, eth_packet]) + if (tunfd < 0) return (uintptr_t)-1; int64_t length = a0; char* data = (char*)a1; + debug_dump_data(data, length); return write(tunfd, data, length); } -#endif // __NR_syz_emit_ethernet +#endif + +#ifdef __NR_syz_extract_tcp_res +// Can't include <linux/ipv6.h>, since it causes +// conflicts due to some structs redefinition. +struct ipv6hdr { + __u8 priority : 4, + version : 4; + __u8 flow_lbl[3]; + + __be16 payload_len; + __u8 nexthdr; + __u8 hop_limit; + + struct in6_addr saddr; + struct in6_addr daddr; +}; + +struct tcp_resources { + int32_t seq; + int32_t ack; +}; + +int read_tun(char* data, int size) +{ + int rv = read(tunfd, data, size); + if (rv < 0) { + if (errno == EAGAIN) + return -1; + fail("tun: read failed with %d, errno: %d", rv, errno); + } + return rv; +} + +void flush_tun() +{ + char data[SYZ_TUN_MAX_PACKET_SIZE]; + while (read_tun(&data[0], sizeof(data)) != -1) + ; +} + +static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) +{ + // syz_extract_tcp_res(res ptr[out, tcp_resources], seq_inc int32, ack_inc int32) + + if (tunfd < 0) + return (uintptr_t)-1; + + char data[SYZ_TUN_MAX_PACKET_SIZE]; + int rv = read_tun(&data[0], sizeof(data)); + if (rv == -1) + return (uintptr_t)-1; + size_t length = rv; + debug_dump_data(data, length); + + struct tcphdr* tcphdr; + + if (length < sizeof(struct ethhdr)) + return (uintptr_t)-1; + struct ethhdr* ethhdr = (struct ethhdr*)&data[0]; + + if (ethhdr->h_proto == htons(ETH_P_IP)) { + if (length < sizeof(struct ethhdr) + sizeof(struct iphdr)) + return (uintptr_t)-1; + struct iphdr* iphdr = (struct iphdr*)&data[sizeof(struct ethhdr)]; + if (iphdr->protocol != IPPROTO_TCP) + return (uintptr_t)-1; + if (length < sizeof(struct ethhdr) + iphdr->ihl * 4 + sizeof(struct tcphdr)) + return (uintptr_t)-1; + tcphdr = (struct tcphdr*)&data[sizeof(struct ethhdr) + iphdr->ihl * 4]; + } else { + if (length < sizeof(struct ethhdr) + sizeof(struct ipv6hdr)) + return (uintptr_t)-1; + struct ipv6hdr* ipv6hdr = (struct ipv6hdr*)&data[sizeof(struct ethhdr)]; + // TODO: parse and skip extension headers. + if (ipv6hdr->nexthdr != IPPROTO_TCP) + return (uintptr_t)-1; + if (length < sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + sizeof(struct tcphdr)) + return (uintptr_t)-1; + tcphdr = (struct tcphdr*)&data[sizeof(struct ethhdr) + sizeof(struct ipv6hdr)]; + } + + struct tcp_resources* res = (struct tcp_resources*)a0; + NONFAILING(res->seq = htonl((ntohl(tcphdr->seq) + (uint32_t)a1))); + NONFAILING(res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32_t)a2))); + + debug("extracted seq: %08x\n", res->seq); + debug("extracted ack: %08x\n", res->ack); + + return 0; +} +#endif struct csum_inet { uint32_t acc; @@ -469,6 +595,10 @@ static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a case __NR_syz_emit_ethernet: return syz_emit_ethernet(a0, a1); #endif +#ifdef __NR_syz_extract_tcp_res + case __NR_syz_extract_tcp_res: + return syz_extract_tcp_res(a0, a1, a2); +#endif #ifdef __NR_syz_kvm_setup_cpu case __NR_syz_kvm_setup_cpu: return syz_kvm_setup_cpu(a0, a1, a2, a3, a4, a5, a6, a7); @@ -530,7 +660,7 @@ static int do_sandbox_none(int executor_pid, bool enable_tun) return pid; sandbox_common(); -#ifdef __NR_syz_emit_ethernet +#ifdef SYZ_TUN_ENABLE setup_tun(executor_pid, enable_tun); #endif @@ -547,7 +677,7 @@ static int do_sandbox_setuid(int executor_pid, bool enable_tun) return pid; sandbox_common(); -#ifdef __NR_syz_emit_ethernet +#ifdef SYZ_TUN_ENABLE setup_tun(executor_pid, enable_tun); #endif @@ -608,7 +738,7 @@ static int namespace_sandbox_proc(void* arg) if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) fail("write of /proc/self/gid_map failed"); -#ifdef __NR_syz_emit_ethernet +#ifdef SYZ_TUN_ENABLE // For sandbox namespace we setup tun after initializing uid mapping, // otherwise ip commands fail. setup_tun(epid, etun); diff --git a/executor/executor.cc b/executor/executor.cc index 955302cab..02792f82f 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -256,6 +256,11 @@ void loop() fail("failed to chdir"); close(kInPipeFd); close(kOutPipeFd); + if (flag_enable_tun) { + // Read all remaining packets from tun to better + // isolate consequently executing programs. + flush_tun(); + } execute_one(); debug("worker exiting\n"); doexit(0); |
