aboutsummaryrefslogtreecommitdiffstats
path: root/csource
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@gmail.com>2017-06-12 19:59:33 +0200
committerGitHub <noreply@github.com>2017-06-12 19:59:33 +0200
commit75fc393514b64e2416c5a2d5a29997981ec12dc4 (patch)
tree4d3d74d2854ca2b69ab4cd930f4984c9a064d0f7 /csource
parent4ca73f9c87f1098a69deb761a8d23f040d8e89db (diff)
parentebcd9ade3f2d3098f069dcc0a0f093ca7b3ed6b1 (diff)
Merge pull request #195 from xairy/up-simplify-csource
Simplify generated C reproducers
Diffstat (limited to 'csource')
-rw-r--r--csource/common.go488
-rw-r--r--csource/csource.go189
-rw-r--r--csource/csource_test.go94
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)