diff options
| author | Andrey Konovalov <andreyknvl@gmail.com> | 2017-06-12 19:59:33 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-06-12 19:59:33 +0200 |
| commit | 75fc393514b64e2416c5a2d5a29997981ec12dc4 (patch) | |
| tree | 4d3d74d2854ca2b69ab4cd930f4984c9a064d0f7 /csource | |
| parent | 4ca73f9c87f1098a69deb761a8d23f040d8e89db (diff) | |
| parent | ebcd9ade3f2d3098f069dcc0a0f093ca7b3ed6b1 (diff) | |
Merge pull request #195 from xairy/up-simplify-csource
Simplify generated C reproducers
Diffstat (limited to 'csource')
| -rw-r--r-- | csource/common.go | 488 | ||||
| -rw-r--r-- | csource/csource.go | 189 | ||||
| -rw-r--r-- | csource/csource_test.go | 94 |
3 files changed, 517 insertions, 254 deletions
diff --git a/csource/common.go b/csource/common.go index cd565d613..8c63b637e 100644 --- a/csource/common.go +++ b/csource/common.go @@ -8,51 +8,135 @@ var commonHeader = ` #define _GNU_SOURCE #endif -#include <sys/ioctl.h> -#include <sys/mman.h> +#include <stdint.h> +#include <string.h> +#include <sys/syscall.h> +#include <unistd.h> +#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) +#include <pthread.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_COLLIDE) +#include <stdlib.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) +#include <setjmp.h> +#include <signal.h> +#include <string.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#endif +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) +#include <errno.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/prctl.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#endif +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) +#include <dirent.h> #include <sys/mount.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE) +#include <errno.h> +#include <sched.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.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> - +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_SETUID) +#include <grp.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NAMESPACE) +#include <fcntl.h> #include <linux/capability.h> -#include <linux/kvm.h> -#include <linux/sched.h> - +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/stat.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE) #include <arpa/inet.h> +#include <errno.h> +#include <fcntl.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> -#include <dirent.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) #include <errno.h> #include <fcntl.h> -#include <grp.h> -#include <pthread.h> -#include <setjmp.h> -#include <signal.h> #include <stdarg.h> #include <stdbool.h> +#include <stdio.h> +#include <sys/stat.h> +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) +#include <stdarg.h> +#include <stdio.h> +#endif +#ifdef __NR_syz_open_dev +#include <fcntl.h> +#include <stdio.h> +#include <sys/stat.h> +#endif +#if defined(__NR_syz_fuse_mount) || defined(__NR_syz_fuseblk_mount) +#include <fcntl.h> +#include <stdio.h> +#include <sys/stat.h> +#endif +#ifdef __NR_syz_open_pts +#include <fcntl.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#endif +#ifdef __NR_syz_kvm_setup_cpu +#include <errno.h> +#include <fcntl.h> +#include <linux/kvm.h> +#include <stdarg.h> #include <stddef.h> -#include <stdint.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#endif +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || defined(SYZ_USE_TMP_DIR) || \ + defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || defined(SYZ_SANDBOX_SETUID) || \ + defined(SYZ_FAULT_INJECTION) || defined(__NR_syz_kvm_setup_cpu) const int kFailStatus = 67; -const int kErrorStatus = 68; const int kRetryStatus = 69; +#endif + +#if defined(SYZ_EXECUTOR) +const int kErrorStatus = 68; +#endif +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || defined(SYZ_USE_TMP_DIR) || \ + defined(SYZ_HANDLE_SEGV) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \ + defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_FAULT_INJECTION) || \ + defined(__NR_syz_kvm_setup_cpu) __attribute__((noreturn)) void doexit(int status) { volatile unsigned i; @@ -60,12 +144,16 @@ __attribute__((noreturn)) void doexit(int status) for (i = 0;; i++) { } } +#endif #if defined(SYZ_EXECUTOR) #define exit use_doexit_instead #define _exit use_doexit_instead #endif +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || defined(SYZ_USE_TMP_DIR) || \ + defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || defined(SYZ_SANDBOX_SETUID) || \ + defined(SYZ_FAULT_INJECTION) || defined(__NR_syz_kvm_setup_cpu) __attribute__((noreturn)) void fail(const char* msg, ...) { int e = errno; @@ -77,6 +165,7 @@ __attribute__((noreturn)) void fail(const char* msg, ...) fprintf(stderr, " (errno %d)\n", e); doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus); } +#endif #if defined(SYZ_EXECUTOR) __attribute__((noreturn)) void error(const char* msg, ...) @@ -91,6 +180,7 @@ __attribute__((noreturn)) void error(const char* msg, ...) } #endif +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) __attribute__((noreturn)) void exitf(const char* msg, ...) { int e = errno; @@ -102,7 +192,9 @@ __attribute__((noreturn)) void exitf(const char* msg, ...) fprintf(stderr, " (errno %d)\n", e); doexit(kRetryStatus); } +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) static int flag_debug; void debug(const char* msg, ...) @@ -115,7 +207,25 @@ void debug(const char* msg, ...) va_end(args); fflush(stdout); } +#endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_BITMASKS) +#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1) + +#define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, (bf_len)) << (bf_off)) + +#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \ + if ((bf_off) == 0 && (bf_len) == 0) { \ + *(type*)(addr) = (type)(val); \ + } else { \ + type new_val = *(type*)(addr); \ + new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \ + new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \ + *(type*)(addr) = new_val; \ + } +#endif + +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) __thread int skip_segv; __thread jmp_buf segv_env; @@ -137,6 +247,12 @@ static void segv_handler(int sig, siginfo_t* info, void* uctx) static void install_segv_handler() { struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); + syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); + memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = segv_handler; sa.sa_flags = SA_NODEFER | SA_SIGINFO; @@ -152,26 +268,23 @@ static void install_segv_handler() } \ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ } +#endif -#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1) - -#define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, (bf_len)) << (bf_off)) - -#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \ - if ((bf_off) == 0 && (bf_len) == 0) { \ - *(type*)(addr) = (type)(val); \ - } else { \ - type new_val = *(type*)(addr); \ - new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \ - new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \ - *(type*)(addr) = new_val; \ - } - -#if defined(__NR_syz_emit_ethernet) || defined(__NR_syz_extract_tcp_res) -#define SYZ_TUN_ENABLE +#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) +static void use_temporary_dir() +{ + char tmpdir_template[] = "./syzkaller.XXXXXX"; + char* tmpdir = mkdtemp(tmpdir_template); + if (!tmpdir) + fail("failed to mkdtemp"); + if (chmod(tmpdir, 0777)) + fail("failed to chmod"); + if (chdir(tmpdir)) + fail("failed to chdir"); +} #endif -#ifdef SYZ_TUN_ENABLE +#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE) static void vsnprintf_check(char* str, size_t size, const char* format, va_list args) { int rv; @@ -278,8 +391,23 @@ static void setup_tun(uint64_t pid, bool enable_tun) if (enable_tun) initialize_tun(pid); } +#endif + +#if defined(SYZ_EXECUTOR) || (defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_extract_tcp_res) || defined(SYZ_REPEAT))) +static 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; +} +#endif -void debug_dump_data(const char* data, int length) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_DEBUG) && defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_emit_ethernet) || defined(__NR_syz_extract_tcp_res))) +static void debug_dump_data(const char* data, int length) { int i; for (i = 0; i < length; i++) { @@ -292,7 +420,39 @@ void debug_dump_data(const char* data, int length) } #endif -#ifdef __NR_syz_emit_ethernet +#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_CHECKSUMS) || defined(__NR_syz_test) +struct csum_inet { + uint32_t acc; +}; + +void csum_inet_init(struct csum_inet* csum) +{ + csum->acc = 0; +} + +void csum_inet_update(struct csum_inet* csum, const uint8_t* data, size_t length) +{ + if (length == 0) + return; + + size_t i; + for (i = 0; i < length - 1; i += 2) + csum->acc += *(uint16_t*)&data[i]; + + if (length & 1) + csum->acc += (uint16_t)data[length - 1]; + + while (csum->acc > 0xffff) + csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16); +} + +uint16_t csum_inet_digest(struct csum_inet* csum) +{ + return ~csum->acc; +} +#endif + +#if defined(SYZ_EXECUTOR) || (defined(__NR_syz_emit_ethernet) && defined(SYZ_TUN_ENABLE)) static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1) { @@ -306,7 +466,16 @@ static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1) } #endif -#ifdef __NR_syz_extract_tcp_res +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_TUN_ENABLE)) +void flush_tun() +{ + char data[SYZ_TUN_MAX_PACKET_SIZE]; + while (read_tun(&data[0], sizeof(data)) != -1) + ; +} +#endif + +#if defined(SYZ_EXECUTOR) || (defined(__NR_syz_extract_tcp_res) && defined(SYZ_TUN_ENABLE)) struct ipv6hdr { __u8 priority : 4, version : 4; @@ -325,24 +494,6 @@ struct tcp_resources { 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) { @@ -393,36 +544,6 @@ static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2) } #endif -struct csum_inet { - uint32_t acc; -}; - -void csum_inet_init(struct csum_inet* csum) -{ - csum->acc = 0; -} - -void csum_inet_update(struct csum_inet* csum, const uint8_t* data, size_t length) -{ - if (length == 0) - return; - - size_t i; - for (i = 0; i < length - 1; i += 2) - csum->acc += *(uint16_t*)&data[i]; - - if (length & 1) - csum->acc += (uint16_t)data[length - 1]; - - while (csum->acc > 0xffff) - csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16); -} - -uint16_t csum_inet_digest(struct csum_inet* csum) -{ - return ~csum->acc; -} - #ifdef __NR_syz_open_dev static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2) { @@ -1205,69 +1326,71 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin } } - struct tss16* tss16 = (struct tss16*)(host_mem + seg_tss16_2.base); - NONFAILING( - struct tss16* tss = tss16; - memset(tss, 0, sizeof(*tss)); - tss->ss0 = tss->ss1 = tss->ss2 = SEL_DS16; - tss->sp0 = tss->sp1 = tss->sp2 = ADDR_STACK0; - tss->ip = ADDR_VAR_USER_CODE2; - tss->flags = (1 << 1); - tss->cs = SEL_CS16; - tss->es = tss->ds = tss->ss = SEL_DS16; - tss->ldt = SEL_LDT); - struct tss16* tss16_cpl3 = (struct tss16*)(host_mem + seg_tss16_cpl3.base); - NONFAILING( - struct tss16* tss = tss16_cpl3; - memset(tss, 0, sizeof(*tss)); - tss->ss0 = tss->ss1 = tss->ss2 = SEL_DS16; - tss->sp0 = tss->sp1 = tss->sp2 = ADDR_STACK0; - tss->ip = ADDR_VAR_USER_CODE2; - tss->flags = (1 << 1); - tss->cs = SEL_CS16_CPL3; - tss->es = tss->ds = tss->ss = SEL_DS16_CPL3; - tss->ldt = SEL_LDT); - struct tss32* tss32 = (struct tss32*)(host_mem + seg_tss32_vm86.base); - NONFAILING( - struct tss32* tss = tss32; - memset(tss, 0, sizeof(*tss)); - tss->ss0 = tss->ss1 = tss->ss2 = SEL_DS32; - tss->sp0 = tss->sp1 = tss->sp2 = ADDR_STACK0; - tss->ip = ADDR_VAR_USER_CODE; - tss->flags = (1 << 1) | (1 << 17); - tss->ldt = SEL_LDT; - tss->cr3 = sregs.cr3; - tss->io_bitmap = offsetof(struct tss32, io_bitmap)); - struct tss32* tss32_cpl3 = (struct tss32*)(host_mem + seg_tss32_2.base); - NONFAILING( - struct tss32* tss = tss32_cpl3; - memset(tss, 0, sizeof(*tss)); - tss->ss0 = tss->ss1 = tss->ss2 = SEL_DS32; - tss->sp0 = tss->sp1 = tss->sp2 = ADDR_STACK0; - tss->ip = ADDR_VAR_USER_CODE; - tss->flags = (1 << 1); - tss->cr3 = sregs.cr3; - tss->es = tss->ds = tss->ss = tss->gs = tss->fs = SEL_DS32; - tss->cs = SEL_CS32; - tss->ldt = SEL_LDT; - tss->cr3 = sregs.cr3; - tss->io_bitmap = offsetof(struct tss32, io_bitmap)); - struct tss64* tss64 = (struct tss64*)(host_mem + seg_tss64.base); - NONFAILING( - struct tss64* tss = tss64; - memset(tss, 0, sizeof(*tss)); - tss->rsp[0] = ADDR_STACK0; - tss->rsp[1] = ADDR_STACK0; - tss->rsp[2] = ADDR_STACK0; - tss->io_bitmap = offsetof(struct tss64, io_bitmap)); - struct tss64* tss64_cpl3 = (struct tss64*)(host_mem + seg_tss64_cpl3.base); - NONFAILING( - struct tss64* tss = tss64_cpl3; - memset(tss, 0, sizeof(*tss)); - tss->rsp[0] = ADDR_STACK0; - tss->rsp[1] = ADDR_STACK0; - tss->rsp[2] = ADDR_STACK0; - tss->io_bitmap = offsetof(struct tss64, io_bitmap)); + struct tss16 tss16; + memset(&tss16, 0, sizeof(tss16)); + tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16; + tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0; + tss16.ip = ADDR_VAR_USER_CODE2; + tss16.flags = (1 << 1); + tss16.cs = SEL_CS16; + tss16.es = tss16.ds = tss16.ss = SEL_DS16; + tss16.ldt = SEL_LDT; + struct tss16* tss16_addr = (struct tss16*)(host_mem + seg_tss16_2.base); + NONFAILING(memcpy(tss16_addr, &tss16, sizeof(tss16))); + + memset(&tss16, 0, sizeof(tss16)); + tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16; + tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0; + tss16.ip = ADDR_VAR_USER_CODE2; + tss16.flags = (1 << 1); + tss16.cs = SEL_CS16_CPL3; + tss16.es = tss16.ds = tss16.ss = SEL_DS16_CPL3; + tss16.ldt = SEL_LDT; + struct tss16* tss16_cpl3_addr = (struct tss16*)(host_mem + seg_tss16_cpl3.base); + NONFAILING(memcpy(tss16_cpl3_addr, &tss16, sizeof(tss16))); + + struct tss32 tss32; + memset(&tss32, 0, sizeof(tss32)); + tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32; + tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0; + tss32.ip = ADDR_VAR_USER_CODE; + tss32.flags = (1 << 1) | (1 << 17); + tss32.ldt = SEL_LDT; + tss32.cr3 = sregs.cr3; + tss32.io_bitmap = offsetof(struct tss32, io_bitmap); + struct tss32* tss32_addr = (struct tss32*)(host_mem + seg_tss32_vm86.base); + NONFAILING(memcpy(tss32_addr, &tss32, sizeof(tss32))); + + memset(&tss32, 0, sizeof(tss32)); + tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32; + tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0; + tss32.ip = ADDR_VAR_USER_CODE; + tss32.flags = (1 << 1); + tss32.cr3 = sregs.cr3; + tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = SEL_DS32; + tss32.cs = SEL_CS32; + tss32.ldt = SEL_LDT; + tss32.cr3 = sregs.cr3; + tss32.io_bitmap = offsetof(struct tss32, io_bitmap); + struct tss32* tss32_cpl3_addr = (struct tss32*)(host_mem + seg_tss32_2.base); + NONFAILING(memcpy(tss32_cpl3_addr, &tss32, sizeof(tss32))); + + struct tss64 tss64; + memset(&tss64, 0, sizeof(tss64)); + tss64.rsp[0] = ADDR_STACK0; + tss64.rsp[1] = ADDR_STACK0; + tss64.rsp[2] = ADDR_STACK0; + tss64.io_bitmap = offsetof(struct tss64, io_bitmap); + struct tss64* tss64_addr = (struct tss64*)(host_mem + seg_tss64.base); + NONFAILING(memcpy(tss64_addr, &tss64, sizeof(tss64))); + + memset(&tss64, 0, sizeof(tss64)); + tss64.rsp[0] = ADDR_STACK0; + tss64.rsp[1] = ADDR_STACK0; + tss64.rsp[2] = ADDR_STACK0; + tss64.io_bitmap = offsetof(struct tss64, io_bitmap); + struct tss64* tss64_cpl3_addr = (struct tss64*)(host_mem + seg_tss64_cpl3.base); + NONFAILING(memcpy(tss64_cpl3_addr, &tss64, sizeof(tss64))); if (text_size > 1000) text_size = 1000; @@ -1319,10 +1442,10 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin val &= ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13) | (1 << 14) | (1 << 15) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21)); regs.rflags ^= val; - NONFAILING(tss16->flags ^= val); - NONFAILING(tss16_cpl3->flags ^= val); - NONFAILING(tss32->flags ^= val); - NONFAILING(tss32_cpl3->flags ^= val); + NONFAILING(tss16_addr->flags ^= val); + NONFAILING(tss16_cpl3_addr->flags ^= val); + NONFAILING(tss32_addr->flags ^= val); + NONFAILING(tss32_cpl3_addr->flags ^= val); break; case 4: seg_cs16.type = val & 0xf; @@ -1476,6 +1599,7 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin #endif #endif +#ifdef SYZ_EXECUTOR static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8) { switch (nr) { @@ -1515,26 +1639,9 @@ static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a #endif } } +#endif -static void setup_main_process() -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_IGN; - syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); - syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); - install_segv_handler(); - - char tmpdir_template[] = "./syzkaller.XXXXXX"; - char* tmpdir = mkdtemp(tmpdir_template); - if (!tmpdir) - fail("failed to mkdtemp"); - if (chmod(tmpdir, 0777)) - fail("failed to chmod"); - if (chdir(tmpdir)) - fail("failed to chdir"); -} - +#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE) static void loop(); static void sandbox_common() @@ -1557,6 +1664,7 @@ static void sandbox_common() unshare(CLONE_NEWIPC); unshare(CLONE_IO); } +#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) static int do_sandbox_none(int executor_pid, bool enable_tun) @@ -1566,7 +1674,7 @@ static int do_sandbox_none(int executor_pid, bool enable_tun) return pid; sandbox_common(); -#ifdef SYZ_TUN_ENABLE +#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE) setup_tun(executor_pid, enable_tun); #endif @@ -1583,7 +1691,7 @@ static int do_sandbox_setuid(int executor_pid, bool enable_tun) return pid; sandbox_common(); -#ifdef SYZ_TUN_ENABLE +#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE) setup_tun(executor_pid, enable_tun); #endif @@ -1642,7 +1750,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 SYZ_TUN_ENABLE +#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE) setup_tun(epid, etun); #endif @@ -1705,7 +1813,7 @@ static int do_sandbox_namespace(int executor_pid, bool enable_tun) } #endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) static void remove_dir(const char* dir) { DIR* dp; @@ -1776,7 +1884,7 @@ retry: } #endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT) +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) static uint64_t current_time_ms() { struct timespec ts; @@ -1807,22 +1915,30 @@ static int inject_fault(int nth) #if defined(SYZ_REPEAT) static void test(); +#if defined(SYZ_WAIT_REPEAT) void loop() { int iter; for (iter = 0;; iter++) { +#ifdef SYZ_USE_TMP_DIR char cwdbuf[256]; sprintf(cwdbuf, "./%d", iter); if (mkdir(cwdbuf, 0777)) fail("failed to mkdir"); +#endif int pid = fork(); if (pid < 0) fail("clone failed"); if (pid == 0) { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); setpgrp(); +#ifdef SYZ_USE_TMP_DIR if (chdir(cwdbuf)) fail("failed to chdir"); +#endif +#ifdef SYZ_TUN_ENABLE + flush_tun(); +#endif test(); doexit(0); } @@ -1841,8 +1957,18 @@ void loop() break; } } +#ifdef SYZ_USE_TMP_DIR remove_dir(cwdbuf); +#endif } } +#else +void loop() +{ + while (1) { + test(); + } +} +#endif #endif ` diff --git a/csource/csource.go b/csource/csource.go index ab585ebec..6caac68bf 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -14,6 +14,7 @@ import ( "io/ioutil" "os" "os/exec" + "regexp" "strings" "unsafe" @@ -22,15 +23,26 @@ import ( ) type Options struct { - Threaded bool - Collide bool - Repeat bool - Procs int - Sandbox string + Threaded bool + Collide bool + Repeat bool + Procs int + Sandbox string + Fault bool // inject fault into FaultCall/FaultNth FaultCall int FaultNth int - Repro bool // generate code for use with repro package + + // These options allow for a more fine-tuned control over the generated C code. + EnableTun bool + UseTmpDir bool + HandleSegv bool + WaitRepeat bool + Debug bool + + // Generate code for use with repro package to prints log messages, + // which allows to distinguish between a hang and an absent crash. + Repro bool } func Write(p *prog.Prog, opts Options) ([]byte, error) { @@ -53,15 +65,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { } fmt.Fprintf(w, "\n") - enableTun := "false" - if _, ok := handled["syz_emit_ethernet"]; ok { - enableTun = "true" - } - if _, ok := handled["syz_extract_tcp_res"]; ok { - enableTun = "true" - } - - hdr, err := preprocessCommonHeader(opts, handled) + hdr, err := preprocessCommonHeader(opts, handled, prog.RequiresBitmasks(p), prog.RequiresChecksums(p)) if err != nil { return nil, err } @@ -75,29 +79,65 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { generateTestFunc(w, opts, calls, "loop") fmt.Fprint(w, "int main()\n{\n") - fmt.Fprintf(w, "\tsetup_main_process();\n") - fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, enableTun) - fmt.Fprint(w, "\tint status = 0;\n") - fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") + if opts.HandleSegv { + fmt.Fprintf(w, "\tinstall_segv_handler();\n") + } + if opts.UseTmpDir { + fmt.Fprintf(w, "\tuse_temporary_dir();\n") + } + if opts.Sandbox != "" { + fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun) + fmt.Fprint(w, "\tint status = 0;\n") + fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") + } else { + if opts.EnableTun { + fmt.Fprintf(w, "\tsetup_tun(0, %v);\n", opts.EnableTun) + } + fmt.Fprint(w, "\tloop();\n") + } fmt.Fprint(w, "\treturn 0;\n}\n") } else { generateTestFunc(w, opts, calls, "test") if opts.Procs <= 1 { fmt.Fprint(w, "int main()\n{\n") - fmt.Fprintf(w, "\tsetup_main_process();\n") - fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, enableTun) - fmt.Fprint(w, "\tint status = 0;\n") - fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") + if opts.HandleSegv { + fmt.Fprintf(w, "\tinstall_segv_handler();\n") + } + if opts.UseTmpDir { + fmt.Fprintf(w, "\tuse_temporary_dir();\n") + } + if opts.Sandbox != "" { + fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun) + fmt.Fprint(w, "\tint status = 0;\n") + fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") + } else { + if opts.EnableTun { + fmt.Fprintf(w, "\tsetup_tun(0, %v);\n", opts.EnableTun) + } + fmt.Fprint(w, "\tloop();\n") + } fmt.Fprint(w, "\treturn 0;\n}\n") } else { fmt.Fprint(w, "int main()\n{\n") 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.Fprintf(w, "\t\t\tsetup_main_process();\n") - fmt.Fprintf(w, "\t\t\tint pid = do_sandbox_%v(i, %v);\n", opts.Sandbox, enableTun) - fmt.Fprint(w, "\t\t\tint status = 0;\n") - fmt.Fprint(w, "\t\t\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") + if opts.HandleSegv { + fmt.Fprintf(w, "\t\t\tinstall_segv_handler();\n") + } + if opts.UseTmpDir { + fmt.Fprintf(w, "\t\t\tuse_temporary_dir();\n") + } + if opts.Sandbox != "" { + fmt.Fprintf(w, "\t\t\tint pid = do_sandbox_%v(i, %v);\n", opts.Sandbox, opts.EnableTun) + fmt.Fprint(w, "\t\t\tint status = 0;\n") + fmt.Fprint(w, "\t\t\twhile (waitpid(pid, &status, __WALL) != pid) {}\n") + } else { + if opts.EnableTun { + fmt.Fprintf(w, "\t\t\tsetup_tun(i, %v);\n", opts.EnableTun) + } + fmt.Fprint(w, "\t\t\tloop();\n") + } fmt.Fprint(w, "\t\t\treturn 0;\n") fmt.Fprint(w, "\t\t}\n") fmt.Fprint(w, "\t}\n") @@ -105,16 +145,31 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { fmt.Fprint(w, "\treturn 0;\n}\n") } } + + // Remove NONFAILING and debug calls. + out0 := w.String() + if !opts.HandleSegv { + re := regexp.MustCompile(`\t*NONFAILING\((.*)\);\n`) + out0 = re.ReplaceAllString(out0, "$1;\n") + } + if !opts.Debug { + re := regexp.MustCompile(`\t*debug\(.*\);\n`) + out0 = re.ReplaceAllString(out0, "") + re = regexp.MustCompile(`\t*debug_dump_data\(.*\);\n`) + out0 = re.ReplaceAllString(out0, "") + } + // Remove duplicate new lines. - out := w.Bytes() + out1 := []byte(out0) for { - out1 := bytes.Replace(out, []byte{'\n', '\n', '\n'}, []byte{'\n', '\n'}, -1) - if len(out) == len(out1) { + out2 := bytes.Replace(out1, []byte{'\n', '\n', '\n'}, []byte{'\n', '\n'}, -1) + if len(out1) == len(out2) { break } - out = out1 + out1 = out2 } - return out, nil + + return out1, nil } func generateTestFunc(w io.Writer, opts Options, calls []string, name string) { @@ -127,7 +182,7 @@ func generateTestFunc(w io.Writer, opts Options, calls []string, name string) { for _, c := range calls { fmt.Fprintf(w, "%s", c) } - fmt.Fprintf(w, "}\n") + fmt.Fprintf(w, "}\n\n") } else { fmt.Fprintf(w, "void *thr(void *arg)\n{\n") fmt.Fprintf(w, "\tswitch ((long)arg) {\n") @@ -147,7 +202,9 @@ func generateTestFunc(w io.Writer, opts Options, calls []string, name string) { fmt.Fprintf(w, "\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n") } fmt.Fprintf(w, "\tmemset(r, -1, sizeof(r));\n") - fmt.Fprintf(w, "\tsrand(getpid());\n") + if opts.Collide { + fmt.Fprintf(w, "\tsrand(getpid());\n") + } fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", len(calls)) fmt.Fprintf(w, "\t\tpthread_create(&th[i], 0, thr, (void*)i);\n") fmt.Fprintf(w, "\t\tusleep(10000);\n") @@ -274,28 +331,49 @@ loop: fmt.Fprintf(w, "\tinject_fault(%v);\n", opts.FaultNth) } meta := sys.Calls[instr] - fmt.Fprintf(w, "\tr[%v] = execute_syscall(__NR_%v", n, meta.CallName) + emitCall := true + if meta.CallName == "syz_test" { + emitCall = false + } + if !opts.EnableTun && (meta.CallName == "syz_emit_ethernet" || meta.CallName == "syz_extract_tcp_res") { + emitCall = false + } + if emitCall { + if meta.Native { + fmt.Fprintf(w, "\tr[%v] = syscall(__NR_%v", n, meta.CallName) + } else { + fmt.Fprintf(w, "\tr[%v] = %v(", n, meta.CallName) + } + } nargs := read() for i := uintptr(0); i < nargs; i++ { typ := read() size := read() _ = size + if emitCall && (meta.Native || i > 0) { + fmt.Fprintf(w, ", ") + } switch typ { case prog.ExecArgConst: - fmt.Fprintf(w, ", 0x%xul", read()) + value := read() + if emitCall { + fmt.Fprintf(w, "0x%xul", value) + } // Bitfields can't be args of a normal syscall, so just ignore them. read() // bit field offset read() // bit field length case prog.ExecArgResult: - fmt.Fprintf(w, ", %v", resultRef()) + ref := resultRef() + if emitCall { + fmt.Fprintf(w, "%v", ref) + } default: panic(fmt.Sprintf("unknown arg type %v", typ)) } } - for i := nargs; i < 9; i++ { - fmt.Fprintf(w, ", 0") + if emitCall { + fmt.Fprintf(w, ");\n") } - fmt.Fprintf(w, ");\n") lastCall = n seenCall = true } @@ -304,9 +382,17 @@ loop: return calls, n } -func preprocessCommonHeader(opts Options, handled map[string]int) (string, error) { +func preprocessCommonHeader(opts Options, handled map[string]int, useBitmasks, useChecksums bool) (string, error) { var defines []string + if useBitmasks { + defines = append(defines, "SYZ_USE_BITMASKS") + } + if useBitmasks { + defines = append(defines, "SYZ_USE_CHECKSUMS") + } switch opts.Sandbox { + case "": + // No sandbox, do nothing. case "none": defines = append(defines, "SYZ_SANDBOX_NONE") case "setuid": @@ -316,12 +402,33 @@ func preprocessCommonHeader(opts Options, handled map[string]int) (string, error default: return "", fmt.Errorf("unknown sandbox mode: %v", opts.Sandbox) } + if opts.Threaded { + defines = append(defines, "SYZ_THREADED") + } + if opts.Collide { + defines = append(defines, "SYZ_COLLIDE") + } if opts.Repeat { defines = append(defines, "SYZ_REPEAT") } if opts.Fault { defines = append(defines, "SYZ_FAULT_INJECTION") } + if opts.EnableTun { + defines = append(defines, "SYZ_TUN_ENABLE") + } + if opts.UseTmpDir { + defines = append(defines, "SYZ_USE_TMP_DIR") + } + if opts.HandleSegv { + defines = append(defines, "SYZ_HANDLE_SEGV") + } + if opts.WaitRepeat { + defines = append(defines, "SYZ_WAIT_REPEAT") + } + if opts.Debug { + defines = append(defines, "SYZ_DEBUG") + } for name, _ := range handled { defines = append(defines, "__NR_"+name) } diff --git a/csource/csource_test.go b/csource/csource_test.go index abff96f72..7db490444 100644 --- a/csource/csource_test.go +++ b/csource/csource_test.go @@ -7,6 +7,7 @@ import ( "fmt" "math/rand" "os" + "reflect" "testing" "time" @@ -16,47 +17,66 @@ import ( func initTest(t *testing.T) (rand.Source, int) { t.Parallel() - iters := 10 - if testing.Short() { - iters = 1 - } + iters := 1 seed := int64(time.Now().UnixNano()) rs := rand.NewSource(seed) t.Logf("seed=%v", seed) return rs, iters } +func enumerateField(opt Options, field int) []Options { + var opts []Options + s := reflect.ValueOf(&opt).Elem() + fldName := s.Type().Field(field).Name + fld := s.Field(field) + if fldName == "Sandbox" { + for _, sandbox := range []string{"", "none", "setuid", "namespace"} { + fld.SetString(sandbox) + opts = append(opts, opt) + } + } else if fldName == "Procs" { + for _, procs := range []int64{1, 4} { + fld.SetInt(procs) + opts = append(opts, opt) + } + } else if fldName == "FaultCall" { + opts = append(opts, opt) + } else if fldName == "FaultNth" { + opts = append(opts, opt) + } else if fld.Kind() == reflect.Bool { + for _, v := range []bool{false, true} { + fld.SetBool(v) + opts = append(opts, opt) + } + } else { + panic(fmt.Sprintf("field '%v' is not boolean", fldName)) + } + return opts +} + +func allOptionsSingle() []Options { + var opts []Options + fields := reflect.TypeOf(Options{}).NumField() + for i := 0; i < fields; i++ { + opts = append(opts, enumerateField(Options{}, i)...) + } + return opts +} + func allOptionsPermutations() []Options { - var options []Options - var opt Options - for _, opt.Threaded = range []bool{false, true} { - for _, opt.Collide = range []bool{false, true} { - for _, opt.Repeat = range []bool{false, true} { - for _, opt.Repro = range []bool{false, true} { - for _, opt.Procs = range []int{1, 4} { - for _, opt.Sandbox = range []string{"none", "setuid", "namespace"} { - for _, opt.Fault = range []bool{false, true} { - if opt.Collide && !opt.Threaded { - continue - } - if !opt.Repeat && opt.Procs != 1 { - continue - } - if testing.Short() && opt.Procs != 1 { - continue - } - options = append(options, opt) - } - } - } - } - } + opts := []Options{ Options{} } + fields := reflect.TypeOf(Options{}).NumField() + for i := 0; i < fields; i++ { + var newOpts []Options + for _, opt := range opts { + newOpts = append(newOpts, enumerateField(opt, i)...) } + opts = newOpts } - return options + return opts } -func TestSyz(t *testing.T) { +func TestOne(t *testing.T) { rs, _ := initTest(t) opts := Options{ Threaded: true, @@ -70,11 +90,21 @@ func TestSyz(t *testing.T) { testOne(t, p, opts) } -func Test(t *testing.T) { +func TestOptions(t *testing.T) { rs, _ := initTest(t) syzProg := prog.GenerateAllSyzProg(rs) t.Logf("syz program:\n%s\n", syzProg.Serialize()) - for i, opts := range allOptionsPermutations() { + permutations := allOptionsSingle() + allPermutations := allOptionsPermutations() + if testing.Short() { + r := rand.New(rs) + for i := 0; i < 32; i++ { + permutations = append(permutations, allPermutations[r.Intn(len(allPermutations))]) + } + } else { + permutations = append(permutations, allPermutations...) + } + for i, opts := range permutations { t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { rs, iters := initTest(t) t.Logf("opts: %+v", opts) |
