diff options
| author | Andrey Konovalov <andreyknvl@google.com> | 2016-10-04 16:12:12 +0200 |
|---|---|---|
| committer | Andrey Konovalov <andreyknvl@google.com> | 2016-11-29 17:39:38 +0100 |
| commit | c5707f5e575f3a4220faede18a51f7a8c7ee1377 (patch) | |
| tree | d7b264b52b8ce35cd6de3db86dc742a30f980bfc | |
| parent | 72e9b239f4d6b71e43acee4ca76de04e893400e8 (diff) | |
executor: emit ethernet traffic
| -rw-r--r-- | csource/common.go | 145 | ||||
| -rw-r--r-- | csource/csource.go | 6 | ||||
| -rw-r--r-- | executor/common.h | 147 | ||||
| -rw-r--r-- | executor/executor.cc | 4 | ||||
| -rwxr-xr-x | extract.sh | 3 | ||||
| -rw-r--r-- | host/host.go | 3 | ||||
| -rw-r--r-- | ipc/ipc.go | 4 | ||||
| -rw-r--r-- | sys/vnet.txt | 11 | ||||
| -rw-r--r-- | sysgen/syscallnr.go | 1 |
9 files changed, 293 insertions, 31 deletions
diff --git a/csource/common.go b/csource/common.go index 5cd07cdfe..186678951 100644 --- a/csource/common.go +++ b/csource/common.go @@ -3,15 +3,33 @@ package csource var commonHeader = ` + #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif + +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/prctl.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <linux/capability.h> +#include <linux/if.h> +#include <linux/if_tun.h> +#include <linux/sched.h> +#include <net/if_arp.h> + +#include <assert.h> #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <grp.h> -#include <linux/capability.h> -#include <linux/sched.h> #include <pthread.h> #include <setjmp.h> #include <signal.h> @@ -21,15 +39,6 @@ var commonHeader = ` #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/ioctl.h> -#include <sys/mount.h> -#include <sys/prctl.h> -#include <sys/resource.h> -#include <sys/stat.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> #include <unistd.h> const int kFailStatus = 67; @@ -115,6 +124,110 @@ static void install_segv_handler() __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ } +#ifdef __NR_syz_emit_ethernet +static void vsnprintf_check(char* str, size_t size, const char* format, va_list args) +{ + int rv; + + rv = vsnprintf(str, size, format, args); + if (rv < 0) + fail("tun: snprintf failed"); + if ((size_t)rv >= size) + fail("tun: string '%s...' doesn't fit into buffer", str); +} + +static void snprintf_check(char* str, size_t size, const char* format, ...) +{ + va_list args; + + va_start(args, format); + vsnprintf_check(str, size, format, args); + va_end(args); +} + +#define COMMAND_MAX_LEN 128 + +static void execute_command(const char* format, ...) +{ + va_list args; + char command[COMMAND_MAX_LEN]; + + va_start(args, format); + + vsnprintf_check(command, sizeof(command), format, args); + if (system(command) < 0) + fail("tun: command \"%s\" failed", &command[0]); + + va_end(args); +} + +int tunfd; + +#define ADDR_MAX_LEN 32 + +#define LOCAL_MAC "aa:aa:aa:aa:aa:%02hx" +#define REMOTE_MAC "bb:bb:bb:bb:bb:%02hx" + +#define LOCAL_IPV4 "192.168.%d.170" +#define REMOTE_IPV4 "192.168.%d.187" + +#define LOCAL_IPV6 "fd00::%02hxaa" +#define REMOTE_IPV6 "fd00::%02hxbb" + +static void initialize_tun(uint64_t pid) +{ + if (getuid() != 0) + return; + + if (pid >= 0xff) + fail("tun: no more than 255 executors"); + int id = pid & 0xff; + + tunfd = open("/dev/net/tun", O_RDWR); + if (tunfd == -1) + fail("tun: can't open /dev/net/tun"); + + char iface[IFNAMSIZ]; + snprintf_check(iface, sizeof(iface), "syz%d", id); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, iface, IFNAMSIZ); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) + fail("tun: ioctl(TUNSETIFF) failed"); + + char local_mac[ADDR_MAX_LEN]; + snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC, id); + char remote_mac[ADDR_MAX_LEN]; + snprintf_check(remote_mac, sizeof(remote_mac), REMOTE_MAC, id); + + char local_ipv4[ADDR_MAX_LEN]; + snprintf_check(local_ipv4, sizeof(local_ipv4), LOCAL_IPV4, id); + char remote_ipv4[ADDR_MAX_LEN]; + snprintf_check(remote_ipv4, sizeof(remote_ipv4), REMOTE_IPV4, id); + + char local_ipv6[ADDR_MAX_LEN]; + snprintf_check(local_ipv6, sizeof(local_ipv6), LOCAL_IPV6, id); + char remote_ipv6[ADDR_MAX_LEN]; + snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, id); + + 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); +} + +static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1) +{ + int64_t length = a0; + char* data = (char*)a1; + return write(tunfd, data, length); +} +#endif + #ifdef __NR_syz_open_dev static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2) { @@ -231,10 +344,14 @@ static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a case __NR_syz_fuseblk_mount: return syz_fuseblk_mount(a0, a1, a2, a3, a4, a5, a6, a7); #endif +#ifdef __NR_syz_emit_ethernet + case __NR_syz_emit_ethernet: + return syz_emit_ethernet(a0, a1); +#endif } } -static void setup_main_process() +static void setup_main_process(uint64_t pid) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); @@ -243,6 +360,10 @@ static void setup_main_process() syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); install_segv_handler(); +#ifdef __NR_syz_emit_ethernet + initialize_tun(pid); +#endif + char tmpdir_template[] = "./syzkaller.XXXXXX"; char* tmpdir = mkdtemp(tmpdir_template); if (!tmpdir) diff --git a/csource/csource.go b/csource/csource.go index 0c4d93ed3..42eca2038 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -59,7 +59,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { generateTestFunc(w, opts, calls, "loop") fmt.Fprint(w, "int main()\n{\n") - fmt.Fprint(w, "\tsetup_main_process();\n") + fmt.Fprint(w, "\tsetup_main_process(0);\n") fmt.Fprintf(w, "\tint pid = do_sandbox_%v();\n", opts.Sandbox) fmt.Fprint(w, "\tint status = 0;\n") fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") @@ -68,7 +68,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { generateTestFunc(w, opts, calls, "test") if opts.Procs <= 1 { fmt.Fprint(w, "int main()\n{\n") - fmt.Fprint(w, "\tsetup_main_process();\n") + fmt.Fprint(w, "\tsetup_main_process(0);\n") fmt.Fprintf(w, "\tint pid = do_sandbox_%v();\n", opts.Sandbox) fmt.Fprint(w, "\tint status = 0;\n") fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") @@ -78,7 +78,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { fmt.Fprint(w, "\tint i;") fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", opts.Procs) fmt.Fprint(w, "\t\tif (fork() == 0) {\n") - fmt.Fprint(w, "\t\t\tsetup_main_process();\n") + fmt.Fprint(w, "\t\t\tsetup_main_process(i);\n") fmt.Fprintf(w, "\t\t\tdo_sandbox_%v();\n", opts.Sandbox) fmt.Fprint(w, "\t\t}\n") fmt.Fprint(w, "\t}\n") diff --git a/executor/common.h b/executor/common.h index dd7a0dfe8..3e8f258d4 100644 --- a/executor/common.h +++ b/executor/common.h @@ -2,15 +2,33 @@ // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. // This file is shared between executor and csource package. + #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif + +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/prctl.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <linux/capability.h> +#include <linux/if.h> +#include <linux/if_tun.h> +#include <linux/sched.h> +#include <net/if_arp.h> + +#include <assert.h> #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <grp.h> -#include <linux/capability.h> -#include <linux/sched.h> #include <pthread.h> #include <setjmp.h> #include <signal.h> @@ -20,22 +38,13 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/ioctl.h> -#include <sys/mount.h> -#include <sys/prctl.h> -#include <sys/resource.h> -#include <sys/stat.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> #include <unistd.h> const int kFailStatus = 67; const int kErrorStatus = 68; const int kRetryStatus = 69; -// logical error (e.g. invalid input program) +// logical error (e.g. invalid input program), use as an assert() alernative __attribute__((noreturn)) void fail(const char* msg, ...) { int e = errno; @@ -117,6 +126,110 @@ static void install_segv_handler() __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ } +#ifdef __NR_syz_emit_ethernet +static void vsnprintf_check(char* str, size_t size, const char* format, va_list args) +{ + int rv; + + rv = vsnprintf(str, size, format, args); + if (rv < 0) + fail("tun: snprintf failed"); + if ((size_t)rv >= size) + fail("tun: string '%s...' doesn't fit into buffer", str); +} + +static void snprintf_check(char* str, size_t size, const char* format, ...) +{ + va_list args; + + va_start(args, format); + vsnprintf_check(str, size, format, args); + va_end(args); +} + +#define COMMAND_MAX_LEN 128 + +static void execute_command(const char* format, ...) +{ + va_list args; + char command[COMMAND_MAX_LEN]; + + va_start(args, format); + + vsnprintf_check(command, sizeof(command), format, args); + if (system(command) < 0) + fail("tun: command \"%s\" failed", &command[0]); + + va_end(args); +} + +int tunfd; + +#define ADDR_MAX_LEN 32 + +#define LOCAL_MAC "aa:aa:aa:aa:aa:%02hx" +#define REMOTE_MAC "bb:bb:bb:bb:bb:%02hx" + +#define LOCAL_IPV4 "192.168.%d.170" +#define REMOTE_IPV4 "192.168.%d.187" + +#define LOCAL_IPV6 "fd00::%02hxaa" +#define REMOTE_IPV6 "fd00::%02hxbb" + +static void initialize_tun(uint64_t pid) +{ + if (getuid() != 0) + return; + + if (pid >= 0xff) + fail("tun: no more than 255 executors"); + int id = pid & 0xff; + + tunfd = open("/dev/net/tun", O_RDWR); + if (tunfd == -1) + fail("tun: can't open /dev/net/tun"); + + char iface[IFNAMSIZ]; + snprintf_check(iface, sizeof(iface), "syz%d", id); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, iface, IFNAMSIZ); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) + fail("tun: ioctl(TUNSETIFF) failed"); + + char local_mac[ADDR_MAX_LEN]; + snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC, id); + char remote_mac[ADDR_MAX_LEN]; + snprintf_check(remote_mac, sizeof(remote_mac), REMOTE_MAC, id); + + char local_ipv4[ADDR_MAX_LEN]; + snprintf_check(local_ipv4, sizeof(local_ipv4), LOCAL_IPV4, id); + char remote_ipv4[ADDR_MAX_LEN]; + snprintf_check(remote_ipv4, sizeof(remote_ipv4), REMOTE_IPV4, id); + + char local_ipv6[ADDR_MAX_LEN]; + snprintf_check(local_ipv6, sizeof(local_ipv6), LOCAL_IPV6, id); + char remote_ipv6[ADDR_MAX_LEN]; + snprintf_check(remote_ipv6, sizeof(remote_ipv6), REMOTE_IPV6, id); + + 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); +} + +static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1) +{ + int64_t length = a0; + char* data = (char*)a1; + return write(tunfd, data, length); +} +#endif // __NR_syz_emit_ethernet + #ifdef __NR_syz_open_dev static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2) { @@ -241,10 +354,14 @@ static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a case __NR_syz_fuseblk_mount: return syz_fuseblk_mount(a0, a1, a2, a3, a4, a5, a6, a7); #endif +#ifdef __NR_syz_emit_ethernet + case __NR_syz_emit_ethernet: + return syz_emit_ethernet(a0, a1); +#endif } } -static void setup_main_process() +static void setup_main_process(uint64_t pid) { // Don't need that SIGCANCEL/SIGSETXID glibc stuff. // SIGCANCEL sent to main thread causes it to exit @@ -256,6 +373,10 @@ static void setup_main_process() syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); install_segv_handler(); +#ifdef __NR_syz_emit_ethernet + initialize_tun(pid); +#endif + char tmpdir_template[] = "./syzkaller.XXXXXX"; char* tmpdir = mkdtemp(tmpdir_template); if (!tmpdir) diff --git a/executor/executor.cc b/executor/executor.cc index b155c578d..85133fa3d 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -161,9 +161,10 @@ int main(int argc, char** argv) flag_sandbox = sandbox_namespace; if (!flag_threaded) flag_collide = false; + uint64_t executor_pid = *((uint64_t*)input_data + 1); cover_open(); - setup_main_process(); + setup_main_process(executor_pid); int pid = -1; switch (flag_sandbox) { @@ -273,6 +274,7 @@ void execute_one() retry: uint64_t* input_pos = (uint64_t*)&input_data[0]; read_input(&input_pos); // flags + read_input(&input_pos); // pid output_pos = (uint32_t*)&output_data[0]; write_output(0); // Number of executed syscalls (updated later). diff --git a/extract.sh b/extract.sh index 027f0e623..ac5c23940 100755 --- a/extract.sh +++ b/extract.sh @@ -21,7 +21,8 @@ fi COMMON_FILES="sys/socket.txt sys/tty.txt sys/perf.txt sys/kvm.txt \ sys/key.txt sys/bpf.txt sys/fuse.txt sys/dri.txt sys/kdbus.txt sys/sctp.txt \ sys/sndseq.txt sys/sndtimer.txt sys/sndcontrol.txt sys/input.txt \ - sys/netlink.txt sys/tun.txt sys/random.txt sys/netrom.txt" + sys/netlink.txt sys/tun.txt sys/random.txt sys/netrom.txt \ + sys/vnet.txt" UPSTREAM_FILES="sys/sys.txt sys/kcm.txt" ANDROID_FILES=sys/tlk_device.txt diff --git a/host/host.go b/host/host.go index a58964e8c..ff4c0c3a8 100644 --- a/host/host.go +++ b/host/host.go @@ -89,6 +89,9 @@ func isSupportedSyzkall(c *sys.Call) bool { case "syz_fuseblk_mount": _, err := os.Stat("/dev/fuse") return err == nil && syscall.Getuid() == 0 + case "syz_emit_ethernet": + _, err := os.Stat("/dev/net/tun") + return err == nil && syscall.Getuid() == 0 default: panic("unknown syzkall: " + c.Name) } diff --git a/ipc/ipc.go b/ipc/ipc.go index dbb2a878d..899a8c7c3 100644 --- a/ipc/ipc.go +++ b/ipc/ipc.go @@ -16,6 +16,7 @@ import ( "sync/atomic" "syscall" "time" + "unsafe" "github.com/google/syzkaller/fileutil" "github.com/google/syzkaller/prog" @@ -121,7 +122,8 @@ func MakeEnv(bin string, timeout time.Duration, flags uint64, pid int) (*Env, er for i := 0; i < 8; i++ { inmem[i] = byte(flags >> (8 * uint(i))) } - inmem = inmem[8:] + *(*uint64)(unsafe.Pointer(&inmem[8])) = uint64(pid) + inmem = inmem[16:] env := &Env{ In: inmem, Out: outmem, diff --git a/sys/vnet.txt b/sys/vnet.txt new file mode 100644 index 000000000..e115e701c --- /dev/null +++ b/sys/vnet.txt @@ -0,0 +1,11 @@ +# Copyright 2016 syzkaller project authors. All rights reserved. +# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +include <linux/types.h> +include <linux/byteorder/generic.h> + +eth_packet { + data array[int8, 0:256] +} [packed] + +syz_emit_ethernet(len len[packet], packet ptr[in, eth_packet]) diff --git a/sysgen/syscallnr.go b/sysgen/syscallnr.go index 81c5009bc..7dc1296fa 100644 --- a/sysgen/syscallnr.go +++ b/sysgen/syscallnr.go @@ -28,6 +28,7 @@ var syzkalls = map[string]uint64{ "syz_open_pts": 1000003, "syz_fuse_mount": 1000004, "syz_fuseblk_mount": 1000005, + "syz_emit_ethernet": 1000006, } func generateExecutorSyscalls(syscalls []Syscall, consts map[string]map[string]uint64) { |
