diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-09-24 11:13:37 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-09-25 15:19:06 +0200 |
| commit | af442a22d956464e7df703b290fa49d78dda3dfa (patch) | |
| tree | b50403630f29373cfb711a711fbfd24d632ce2ba | |
| parent | 255e8b5e54e93fc77302a546dbb7a932412d1bde (diff) | |
executor, sys/windows: initial windows support
| -rw-r--r-- | docs/windows.md | 18 | ||||
| -rw-r--r-- | executor/common.h | 67 | ||||
| -rw-r--r-- | executor/common_fuchsia.h | 66 | ||||
| -rw-r--r-- | executor/common_linux.h | 65 | ||||
| -rw-r--r-- | executor/common_windows.h | 50 | ||||
| -rw-r--r-- | executor/executor.h | 22 | ||||
| -rw-r--r-- | executor/executor_fuchsia.cc | 66 | ||||
| -rw-r--r-- | executor/executor_linux.cc | 53 | ||||
| -rw-r--r-- | executor/executor_linux.h | 66 | ||||
| -rw-r--r-- | executor/executor_posix.h | 82 | ||||
| -rw-r--r-- | executor/executor_windows.cc | 85 | ||||
| -rw-r--r-- | executor/executor_windows.h | 74 | ||||
| -rw-r--r-- | executor/syscalls_windows.h | 14 | ||||
| -rw-r--r-- | pkg/ast/scanner.go | 3 | ||||
| -rw-r--r-- | pkg/csource/common.go | 113 | ||||
| -rw-r--r-- | pkg/csource/csource_test.go | 6 | ||||
| -rw-r--r-- | sys/sys.go | 1 | ||||
| -rw-r--r-- | sys/syz-extract/extract.go | 38 | ||||
| -rw-r--r-- | sys/syz-extract/fuchsia.go | 25 | ||||
| -rw-r--r-- | sys/syz-extract/linux.go | 33 | ||||
| -rw-r--r-- | sys/syz-extract/windows.go | 94 | ||||
| -rw-r--r-- | sys/syz-sysgen/sysgen.go | 4 | ||||
| -rw-r--r-- | sys/targets/targets.go | 9 | ||||
| -rw-r--r-- | sys/windows/amd64.go | 129 | ||||
| -rw-r--r-- | sys/windows/init.go | 61 | ||||
| -rw-r--r-- | sys/windows/sys.txt | 31 | ||||
| -rw-r--r-- | sys/windows/sys_amd64.const | bin | 0 -> 2029 bytes |
27 files changed, 970 insertions, 305 deletions
diff --git a/docs/windows.md b/docs/windows.md new file mode 100644 index 000000000..b89caf55c --- /dev/null +++ b/docs/windows.md @@ -0,0 +1,18 @@ +# Windows + +To update descriptions run (assumes `cl` cross-compiler is in PATH): +``` +syz-extract -os=windows +syz-sysgen +``` + +To build binaries: +``` +go build -o bin/windows_amd64/syz-stress.exe ./tools/syz-stress +cl executor\executor_windows.cc /EHsc -o bin\windows_amd64\syz-executor.exe +``` + +To run: +``` +bin\windows_amd64\syz-stress.exe -executor c:\full\path\to\bin\windows_amd64\syz-executor.exe -cover=0 +```
\ No newline at end of file diff --git a/executor/common.h b/executor/common.h index 9eb5ea2c5..f5b525cc4 100644 --- a/executor/common.h +++ b/executor/common.h @@ -5,10 +5,6 @@ #include <stdint.h> #include <string.h> -#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) -#include <pthread.h> -#include <stdlib.h> -#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) #include <errno.h> #include <stdarg.h> @@ -21,15 +17,6 @@ #include <signal.h> #include <string.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/time.h> -#include <sys/wait.h> -#include <time.h> -#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) #include <stdarg.h> #include <stdio.h> @@ -64,7 +51,7 @@ const int kErrorStatus = 68; 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) // logical error (e.g. invalid input program), use as an assert() alernative -__attribute__((noreturn)) static void fail(const char* msg, ...) +NORETURN static void fail(const char* msg, ...) { int e = errno; fflush(stdout); @@ -81,7 +68,7 @@ __attribute__((noreturn)) static void fail(const char* msg, ...) #if defined(SYZ_EXECUTOR) // kernel error (e.g. wrong syscall return value) -__attribute__((noreturn)) static void error(const char* msg, ...) +NORETURN static void error(const char* msg, ...) { fflush(stdout); va_list args; @@ -95,7 +82,7 @@ __attribute__((noreturn)) static void error(const char* msg, ...) #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) // just exit (e.g. due to temporal ENOMEM error) -__attribute__((noreturn)) static void exitf(const char* msg, ...) +NORETURN static void exitf(const char* msg, ...) { int e = errno; fflush(stdout); @@ -139,41 +126,6 @@ static void debug(const char* msg, ...) } #endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) -static __thread int skip_segv; -static __thread jmp_buf segv_env; - -static void segv_handler(int sig, siginfo_t* info, void* uctx) -{ - // Generated programs can contain bad (unmapped/protected) addresses, - // which cause SIGSEGVs during copyin/copyout. - // This handler ignores such crashes to allow the program to proceed. - // We additionally opportunistically check that the faulty address - // is not within executable data region, because such accesses can corrupt - // output region and then fuzzer will fail on corrupted data. - uintptr_t addr = (uintptr_t)info->si_addr; - const uintptr_t prog_start = 1 << 20; - const uintptr_t prog_end = 100 << 20; - if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { - debug("SIGSEGV on %p, skipping\n", addr); - _longjmp(segv_env, 1); - } - debug("SIGSEGV on %p, exiting\n", addr); - doexit(sig); - for (;;) { - } -} - -#define NONFAILING(...) \ - { \ - __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ - if (_setjmp(segv_env) == 0) { \ - __VA_ARGS__; \ - } \ - __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ - } -#endif - #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_CHECKSUMS) struct csum_inet { uint32_t acc; @@ -204,15 +156,4 @@ static uint16_t csum_inet_digest(struct csum_inet* csum) { return ~csum->acc; } -#endif - -#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) -static uint64_t current_time_ms() -{ - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts)) - fail("clock_gettime failed"); - return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; -} -#endif +#endif
\ No newline at end of file diff --git a/executor/common_fuchsia.h b/executor/common_fuchsia.h index e6ccddffe..004046020 100644 --- a/executor/common_fuchsia.h +++ b/executor/common_fuchsia.h @@ -3,14 +3,53 @@ // This file is shared between executor and csource package. +#include <unistd.h> #include <zircon/process.h> #include <zircon/syscalls.h> +#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) +#include <pthread.h> +#include <stdlib.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/time.h> +#include <sys/wait.h> +#include <time.h> +#endif #define doexit exit +#define NORETURN __attribute__((noreturn)) #include "common.h" #if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) +static __thread int skip_segv; +static __thread jmp_buf segv_env; + +static void segv_handler(int sig, siginfo_t* info, void* uctx) +{ + // Generated programs can contain bad (unmapped/protected) addresses, + // which cause SIGSEGVs during copyin/copyout. + // This handler ignores such crashes to allow the program to proceed. + // We additionally opportunistically check that the faulty address + // is not within executable data region, because such accesses can corrupt + // output region and then fuzzer will fail on corrupted data. + uintptr_t addr = (uintptr_t)info->si_addr; + const uintptr_t prog_start = 1 << 20; + const uintptr_t prog_end = 100 << 20; + if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { + debug("SIGSEGV on %p, skipping\n", addr); + _longjmp(segv_env, 1); + } + debug("SIGSEGV on %p, exiting\n", addr); + doexit(sig); + for (;;) { + } +} + static void install_segv_handler() { struct sigaction sa; @@ -21,6 +60,33 @@ static void install_segv_handler() sigaction(SIGSEGV, &sa, NULL); sigaction(SIGBUS, &sa, NULL); } + +#define NONFAILING(...) \ + { \ + __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + if (_setjmp(segv_env) == 0) { \ + __VA_ARGS__; \ + } \ + __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + } +#endif + +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) +static uint64_t current_time_ms() +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + fail("clock_gettime failed"); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} +#endif + +#if defined(SYZ_EXECUTOR) +static void sleep_ms(uint64_t ms) +{ + usleep(ms * 1000); +} #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) diff --git a/executor/common_linux.h b/executor/common_linux.h index dd7d0ac31..3ad7d374f 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -9,6 +9,19 @@ #include <sys/syscall.h> #include <unistd.h> +#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) +#include <pthread.h> +#include <stdlib.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/time.h> +#include <sys/wait.h> +#include <time.h> +#endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) #include <sys/prctl.h> #endif @@ -113,6 +126,7 @@ __attribute__((noreturn)) static void doexit(int status) for (i = 0;; i++) { } } +#define NORETURN __attribute__((noreturn)) #endif #if defined(SYZ_EXECUTOR) @@ -124,6 +138,30 @@ __attribute__((noreturn)) static void doexit(int status) #include "common.h" #if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) +static __thread int skip_segv; +static __thread jmp_buf segv_env; + +static void segv_handler(int sig, siginfo_t* info, void* uctx) +{ + // Generated programs can contain bad (unmapped/protected) addresses, + // which cause SIGSEGVs during copyin/copyout. + // This handler ignores such crashes to allow the program to proceed. + // We additionally opportunistically check that the faulty address + // is not within executable data region, because such accesses can corrupt + // output region and then fuzzer will fail on corrupted data. + uintptr_t addr = (uintptr_t)info->si_addr; + const uintptr_t prog_start = 1 << 20; + const uintptr_t prog_end = 100 << 20; + if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { + debug("SIGSEGV on %p, skipping\n", addr); + _longjmp(segv_env, 1); + } + debug("SIGSEGV on %p, exiting\n", addr); + doexit(sig); + for (;;) { + } +} + static void install_segv_handler() { struct sigaction sa; @@ -142,6 +180,33 @@ static void install_segv_handler() sigaction(SIGSEGV, &sa, NULL); sigaction(SIGBUS, &sa, NULL); } + +#define NONFAILING(...) \ + { \ + __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + if (_setjmp(segv_env) == 0) { \ + __VA_ARGS__; \ + } \ + __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + } +#endif + +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) +static uint64_t current_time_ms() +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + fail("clock_gettime failed"); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} +#endif + +#if defined(SYZ_EXECUTOR) +static void sleep_ms(uint64_t ms) +{ + usleep(ms * 1000); +} #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) diff --git a/executor/common_windows.h b/executor/common_windows.h new file mode 100644 index 000000000..80c197a4a --- /dev/null +++ b/executor/common_windows.h @@ -0,0 +1,50 @@ +// Copyright 2017 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. + +// This file is shared between executor and csource package. + +#include <windows.h> + +#define doexit exit +#define NORETURN + +#include "common.h" + +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) +static void install_segv_handler() +{ +} + +// TODO(dvyukov): implement me +#define NONFAILING(...) \ + __try { \ + __VA_ARGS__; \ + } __except (EXCEPTION_EXECUTE_HANDLER) { \ + } +#endif + +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) +static uint64_t current_time_ms() +{ + return GetTickCount64(); +} +#endif + +#if defined(SYZ_EXECUTOR) +static void sleep_ms(uint64_t ms) +{ + Sleep(ms); +} +#endif + +#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) +static int inject_fault(int nth) +{ + return 0; +} + +static int fault_injected(int fail_fd) +{ + return 0; +} +#endif diff --git a/executor/executor.h b/executor/executor.h index 08112ec5d..0eb0e4fc4 100644 --- a/executor/executor.h +++ b/executor/executor.h @@ -3,7 +3,6 @@ #include <algorithm> #include <errno.h> -#include <pthread.h> #include <signal.h> #include <stdarg.h> #include <stddef.h> @@ -12,7 +11,6 @@ #include <stdlib.h> #include <string.h> #include <time.h> -#include <unistd.h> #ifndef GIT_REVISION #define GIT_REVISION "unknown" @@ -77,7 +75,7 @@ const uint64_t arg_csum_chunk_const = 1; struct thread_t { bool created; int id; - pthread_t th; + osthread_t th; // TODO(dvyukov): this assumes 64-bit kernel. This must be "kernel long" somehow. uint64_t* cover_data; // Pointer to the size of coverage (stored as first word of memory). @@ -135,12 +133,6 @@ void handle_completion(thread_t* th); void execute_call(thread_t* th); void thread_create(thread_t* th, int id); void* worker_thread(void* arg); -void event_init(event_t* ev); -void event_set(event_t* ev); -void event_reset(event_t* ev); -void event_wait(event_t* ev); -bool event_isset(event_t* ev); -bool event_timedwait(event_t* ev, uint64_t timeout_ms); uint32_t* write_output(uint32_t v); void write_completed(uint32_t completed); uint64_t read_input(uint64_t** input_posp, bool peek = false); @@ -282,7 +274,7 @@ retry: fail("running = %d", running); if (running > 0) { bool last = read_input(&input_pos, true) == instr_eof; - usleep(last ? 1000 : 100); + sleep_ms(last ? 10 : 1); for (int i = 0; i < kMaxThreads; i++) { th = &threads[i]; if (!th->handled && event_isset(&th->done)) @@ -445,14 +437,8 @@ void thread_create(thread_t* th, int id) event_init(&th->ready); event_init(&th->done); event_set(&th->done); - if (flag_threaded) { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, 128 << 10); - if (pthread_create(&th->th, &attr, worker_thread, th)) - exitf("pthread_create failed"); - pthread_attr_destroy(&attr); - } + if (flag_threaded) + thread_start(&th->th, worker_thread, th); } void* worker_thread(void* arg) diff --git a/executor/executor_fuchsia.cc b/executor/executor_fuchsia.cc index 4ff293350..7bb7146e1 100644 --- a/executor/executor_fuchsia.cc +++ b/executor/executor_fuchsia.cc @@ -6,11 +6,7 @@ #define SYZ_EXECUTOR #include "common_fuchsia.h" -struct event_t { - pthread_mutex_t mu; - pthread_cond_t cv; - bool state; -}; +#include "executor_posix.h" #include "executor.h" @@ -85,63 +81,3 @@ uint32_t* write_output(uint32_t v) void write_completed(uint32_t completed) { } - -void event_init(event_t* ev) -{ - if (pthread_mutex_init(&ev->mu, 0)) - fail("pthread_mutex_init failed"); - if (pthread_cond_init(&ev->cv, 0)) - fail("pthread_cond_init failed"); - ev->state = false; -} - -void event_reset(event_t* ev) -{ - ev->state = false; -} - -void event_set(event_t* ev) -{ - pthread_mutex_lock(&ev->mu); - if (ev->state) - fail("event already set"); - ev->state = true; - pthread_mutex_unlock(&ev->mu); - pthread_cond_broadcast(&ev->cv); -} - -void event_wait(event_t* ev) -{ - pthread_mutex_lock(&ev->mu); - while (!ev->state) - pthread_cond_wait(&ev->cv, &ev->mu); - pthread_mutex_unlock(&ev->mu); -} - -bool event_isset(event_t* ev) -{ - pthread_mutex_lock(&ev->mu); - bool res = ev->state; - pthread_mutex_unlock(&ev->mu); - return res; -} - -bool event_timedwait(event_t* ev, uint64_t timeout_ms) -{ - pthread_mutex_lock(&ev->mu); - uint64_t start = current_time_ms(); - for (;;) { - if (ev->state) - break; - uint64_t now = current_time_ms(); - if (now - start > timeout_ms) - break; - timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = (timeout_ms - (now - start)) * 1000 * 1000; - pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); - } - bool res = ev->state; - pthread_mutex_unlock(&ev->mu); - return res; -} diff --git a/executor/executor_linux.cc b/executor/executor_linux.cc index 85a0b29c8..7a26d71c0 100644 --- a/executor/executor_linux.cc +++ b/executor/executor_linux.cc @@ -15,12 +15,11 @@ #include <sys/wait.h> #include <unistd.h> -struct event_t { - int state; -}; - #define SYZ_EXECUTOR #include "common_linux.h" + +#include "executor_linux.h" + #include "executor.h" #include "syscalls_linux.h" @@ -327,49 +326,3 @@ void write_completed(uint32_t completed) { __atomic_store_n(output_data, completed, __ATOMIC_RELEASE); } - -void event_init(event_t* ev) -{ - ev->state = 0; -} - -void event_reset(event_t* ev) -{ - ev->state = 0; -} - -void event_set(event_t* ev) -{ - if (ev->state) - fail("event already set"); - __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); - syscall(SYS_futex, &ev->state, FUTEX_WAKE); -} - -void event_wait(event_t* ev) -{ - while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) - syscall(SYS_futex, &ev->state, FUTEX_WAIT, 0, 0); -} - -bool event_isset(event_t* ev) -{ - return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); -} - -bool event_timedwait(event_t* ev, uint64_t timeout_ms) -{ - uint64_t start = current_time_ms(); - uint64_t now = start; - for (;;) { - timespec ts = {}; - ts.tv_sec = 0; - ts.tv_nsec = (timeout_ms - (now - start)) * 1000 * 1000; - syscall(SYS_futex, &ev->state, FUTEX_WAIT, 0, &ts); - if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED)) - return true; - now = current_time_ms(); - if (now - start > timeout_ms) - return false; - } -} diff --git a/executor/executor_linux.h b/executor/executor_linux.h new file mode 100644 index 000000000..5ede578f1 --- /dev/null +++ b/executor/executor_linux.h @@ -0,0 +1,66 @@ +// Copyright 2017 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 <pthread.h> + +typedef pthread_t osthread_t; + +void thread_start(osthread_t* t, void* (*fn)(void*), void* arg) +{ + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 128 << 10); + if (pthread_create(t, &attr, fn, arg)) + exitf("pthread_create failed"); + pthread_attr_destroy(&attr); +} + +struct event_t { + int state; +}; + +void event_init(event_t* ev) +{ + ev->state = 0; +} + +void event_reset(event_t* ev) +{ + ev->state = 0; +} + +void event_set(event_t* ev) +{ + if (ev->state) + fail("event already set"); + __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); + syscall(SYS_futex, &ev->state, FUTEX_WAKE); +} + +void event_wait(event_t* ev) +{ + while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) + syscall(SYS_futex, &ev->state, FUTEX_WAIT, 0, 0); +} + +bool event_isset(event_t* ev) +{ + return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); +} + +bool event_timedwait(event_t* ev, uint64_t timeout_ms) +{ + uint64_t start = current_time_ms(); + uint64_t now = start; + for (;;) { + timespec ts = {}; + ts.tv_sec = 0; + ts.tv_nsec = (timeout_ms - (now - start)) * 1000 * 1000; + syscall(SYS_futex, &ev->state, FUTEX_WAIT, 0, &ts); + if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED)) + return true; + now = current_time_ms(); + if (now - start > timeout_ms) + return false; + } +} diff --git a/executor/executor_posix.h b/executor/executor_posix.h new file mode 100644 index 000000000..e9b06b807 --- /dev/null +++ b/executor/executor_posix.h @@ -0,0 +1,82 @@ +// Copyright 2017 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 <pthread.h> + +typedef pthread_t osthread_t; + +void thread_start(osthread_t* t, void* (*fn)(void*), void* arg) +{ + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 128 << 10); + if (pthread_create(t, &attr, fn, arg)) + exitf("pthread_create failed"); + pthread_attr_destroy(&attr); +} + +struct event_t { + pthread_mutex_t mu; + pthread_cond_t cv; + bool state; +}; + +void event_init(event_t* ev) +{ + if (pthread_mutex_init(&ev->mu, 0)) + fail("pthread_mutex_init failed"); + if (pthread_cond_init(&ev->cv, 0)) + fail("pthread_cond_init failed"); + ev->state = false; +} + +void event_reset(event_t* ev) +{ + ev->state = false; +} + +void event_set(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + if (ev->state) + fail("event already set"); + ev->state = true; + pthread_mutex_unlock(&ev->mu); + pthread_cond_broadcast(&ev->cv); +} + +void event_wait(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + while (!ev->state) + pthread_cond_wait(&ev->cv, &ev->mu); + pthread_mutex_unlock(&ev->mu); +} + +bool event_isset(event_t* ev) +{ + pthread_mutex_lock(&ev->mu); + bool res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} + +bool event_timedwait(event_t* ev, uint64_t timeout_ms) +{ + pthread_mutex_lock(&ev->mu); + uint64_t start = current_time_ms(); + for (;;) { + if (ev->state) + break; + uint64_t now = current_time_ms(); + if (now - start > timeout_ms) + break; + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = (timeout_ms - (now - start)) * 1000 * 1000; + pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); + } + bool res = ev->state; + pthread_mutex_unlock(&ev->mu); + return res; +} diff --git a/executor/executor_windows.cc b/executor/executor_windows.cc new file mode 100644 index 000000000..7b30e1a96 --- /dev/null +++ b/executor/executor_windows.cc @@ -0,0 +1,85 @@ +// Copyright 2017 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. + +// +build + +#include <io.h> + +#define SYZ_EXECUTOR +#include "common_windows.h" + +#include "executor_windows.h" + +#include "executor.h" + +#include "syscalls_windows.h" + +char input_data[kMaxInput]; +uint32_t output; + +int main(int argc, char** argv) +{ + if (argc == 2 && strcmp(argv[1], "version") == 0) { + puts("linux " GOARCH " " SYZ_REVISION " " GIT_REVISION); + return 0; + } + + int pos = 0; + for (;;) { + int rv = _read(0, input_data + pos, sizeof(input_data) - pos); + if (rv < 0) + fail("read failed"); + if (rv == 0) + break; + pos += rv; + } + if (pos < 24) + fail("truncated input"); + + uint64_t flags = *(uint64_t*)input_data; + flag_debug = flags & (1 << 0); + flag_threaded = flags & (1 << 2); + flag_collide = flags & (1 << 3); + if (!flag_threaded) + flag_collide = false; + uint64_t executor_pid = *((uint64_t*)input_data + 2); + debug("input %d, threaded=%d collide=%d pid=%llu\n", + pos, flag_threaded, flag_collide, executor_pid); + + execute_one(((uint64_t*)input_data) + 3); + return 0; +} + +long execute_syscall(call_t* c, long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) +{ + debug("%s = %p\n", c->name, c->call); + long res = c->call(a0, a1, a2, a3, a4, a5, a6, a7, a8); + debug("%s = %ld\n", c->name, res); + return res; +} + +void cover_open() +{ +} + +void cover_enable(thread_t* th) +{ +} + +void cover_reset(thread_t* th) +{ +} + +uint64_t read_cover_size(thread_t* th) +{ + return 0; +} + +uint32_t* write_output(uint32_t v) +{ + return &output; +} + +void write_completed(uint32_t completed) +{ +}
\ No newline at end of file diff --git a/executor/executor_windows.h b/executor/executor_windows.h new file mode 100644 index 000000000..5b788e095 --- /dev/null +++ b/executor/executor_windows.h @@ -0,0 +1,74 @@ +// Copyright 2017 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 <windows.h> + +typedef HANDLE osthread_t; + +void thread_start(osthread_t* t, void* (*fn)(void*), void* arg) +{ + *t = CreateThread(NULL, 128 << 10, (LPTHREAD_START_ROUTINE)fn, arg, 0, NULL); + if (*t == NULL) + exitf("CreateThread failed"); +} + +struct event_t { + CRITICAL_SECTION cs; + CONDITION_VARIABLE cv; + int state; +}; + +void event_init(event_t* ev) +{ + InitializeCriticalSection(&ev->cs); + InitializeConditionVariable(&ev->cv); + ev->state = 0; +} + +void event_reset(event_t* ev) +{ + ev->state = 0; +} + +void event_set(event_t* ev) +{ + EnterCriticalSection(&ev->cs); + if (ev->state) + fail("event already set"); + ev->state = true; + LeaveCriticalSection(&ev->cs); + WakeAllConditionVariable(&ev->cv); +} + +void event_wait(event_t* ev) +{ + EnterCriticalSection(&ev->cs); + while (!ev->state) + SleepConditionVariableCS(&ev->cv, &ev->cs, INFINITE); + LeaveCriticalSection(&ev->cs); +} + +bool event_isset(event_t* ev) +{ + EnterCriticalSection(&ev->cs); + bool res = ev->state; + LeaveCriticalSection(&ev->cs); + return res; +} + +bool event_timedwait(event_t* ev, uint64_t timeout_ms) +{ + EnterCriticalSection(&ev->cs); + uint64_t start = current_time_ms(); + for (;;) { + if (ev->state) + break; + uint64_t now = current_time_ms(); + if (now - start > timeout_ms) + break; + SleepConditionVariableCS(&ev->cv, &ev->cs, timeout_ms - (now - start)); + } + bool res = ev->state; + LeaveCriticalSection(&ev->cs); + return res; +} diff --git a/executor/syscalls_windows.h b/executor/syscalls_windows.h new file mode 100644 index 000000000..517845c25 --- /dev/null +++ b/executor/syscalls_windows.h @@ -0,0 +1,14 @@ +// AUTOGENERATED FILE + +#if defined(_M_X64) || 0 +#define GOARCH "amd64" +#define SYZ_REVISION "5abfe477fc941d0acacdeae7934602a90c22d5bc" + +unsigned syscall_count = 3; +call_t syscalls[] = { + {"CloseHandle", 0, (syscall_t)CloseHandle}, + {"CreateFileA", 0, (syscall_t)CreateFileA}, + {"VirtualAlloc", 0, (syscall_t)VirtualAlloc}, + +}; +#endif diff --git a/pkg/ast/scanner.go b/pkg/ast/scanner.go index 8a15dd8f9..bd2171506 100644 --- a/pkg/ast/scanner.go +++ b/pkg/ast/scanner.go @@ -241,6 +241,9 @@ func (s *scanner) Ok() bool { func (s *scanner) next() { s.off++ + for s.off < len(s.data) && s.data[s.off] == '\r' { + s.off++ + } if s.off == len(s.data) { // Always emit NEWLINE before EOF. // Makes lots of things simpler as we always diff --git a/pkg/csource/common.go b/pkg/csource/common.go index 588a0cd45..c38f805da 100644 --- a/pkg/csource/common.go +++ b/pkg/csource/common.go @@ -10,6 +10,19 @@ var commonHeader = ` #include <sys/syscall.h> #include <unistd.h> +#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) +#include <pthread.h> +#include <stdlib.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/time.h> +#include <sys/wait.h> +#include <time.h> +#endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) #include <sys/prctl.h> #endif @@ -103,6 +116,7 @@ __attribute__((noreturn)) static void doexit(int status) for (i = 0;; i++) { } } +#define NORETURN __attribute__((noreturn)) #endif #if defined(SYZ_EXECUTOR) @@ -114,10 +128,6 @@ __attribute__((noreturn)) static void doexit(int status) #include <stdint.h> #include <string.h> -#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) -#include <pthread.h> -#include <stdlib.h> -#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) #include <errno.h> #include <stdarg.h> @@ -130,15 +140,6 @@ __attribute__((noreturn)) static void doexit(int status) #include <signal.h> #include <string.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/time.h> -#include <sys/wait.h> -#include <time.h> -#endif #if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG) #include <stdarg.h> #include <stdio.h> @@ -171,7 +172,7 @@ const int kErrorStatus = 68; #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)) static void fail(const char* msg, ...) +NORETURN static void fail(const char* msg, ...) { int e = errno; fflush(stdout); @@ -185,7 +186,7 @@ __attribute__((noreturn)) static void fail(const char* msg, ...) #endif #if defined(SYZ_EXECUTOR) -__attribute__((noreturn)) static void error(const char* msg, ...) +NORETURN static void error(const char* msg, ...) { fflush(stdout); va_list args; @@ -198,7 +199,7 @@ __attribute__((noreturn)) static void error(const char* msg, ...) #endif #if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) -__attribute__((noreturn)) static void exitf(const char* msg, ...) +NORETURN static void exitf(const char* msg, ...) { int e = errno; fflush(stdout); @@ -242,35 +243,6 @@ static void debug(const char* msg, ...) } #endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) -static __thread int skip_segv; -static __thread jmp_buf segv_env; - -static void segv_handler(int sig, siginfo_t* info, void* uctx) -{ - uintptr_t addr = (uintptr_t)info->si_addr; - const uintptr_t prog_start = 1 << 20; - const uintptr_t prog_end = 100 << 20; - if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { - debug("SIGSEGV on %p, skipping\n", addr); - _longjmp(segv_env, 1); - } - debug("SIGSEGV on %p, exiting\n", addr); - doexit(sig); - for (;;) { - } -} - -#define NONFAILING(...) \ - { \ - __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ - if (_setjmp(segv_env) == 0) { \ - __VA_ARGS__; \ - } \ - __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ - } -#endif - #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_CHECKSUMS) struct csum_inet { uint32_t acc; @@ -302,19 +274,25 @@ static uint16_t csum_inet_digest(struct csum_inet* csum) return ~csum->acc; } #endif +#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) +static __thread int skip_segv; +static __thread jmp_buf segv_env; -#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) -static uint64_t current_time_ms() +static void segv_handler(int sig, siginfo_t* info, void* uctx) { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts)) - fail("clock_gettime failed"); - return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; + uintptr_t addr = (uintptr_t)info->si_addr; + const uintptr_t prog_start = 1 << 20; + const uintptr_t prog_end = 100 << 20; + if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { + debug("SIGSEGV on %p, skipping\n", addr); + _longjmp(segv_env, 1); + } + debug("SIGSEGV on %p, exiting\n", addr); + doexit(sig); + for (;;) { + } } -#endif -#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV) static void install_segv_handler() { struct sigaction sa; @@ -330,6 +308,33 @@ static void install_segv_handler() sigaction(SIGSEGV, &sa, NULL); sigaction(SIGBUS, &sa, NULL); } + +#define NONFAILING(...) \ + { \ + __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + if (_setjmp(segv_env) == 0) { \ + __VA_ARGS__; \ + } \ + __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + } +#endif + +#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) +static uint64_t current_time_ms() +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + fail("clock_gettime failed"); + return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; +} +#endif + +#if defined(SYZ_EXECUTOR) +static void sleep_ms(uint64_t ms) +{ + usleep(ms * 1000); +} #endif #if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR) diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go index fac64be82..6334c40bf 100644 --- a/pkg/csource/csource_test.go +++ b/pkg/csource/csource_test.go @@ -101,8 +101,10 @@ func TestOne(t *testing.T) { } for _, target := range prog.AllTargets() { if target.OS == "fuchsia" { - // TODO(dvyukov): support fuchsia - continue + continue // TODO(dvyukov): support fuchsia + } + if target.OS == "windows" { + continue // TODO(dvyukov): support windows } target := target t.Run(target.OS+"/"+target.Arch, func(t *testing.T) { diff --git a/sys/sys.go b/sys/sys.go index 87abb9997..7ba783e5e 100644 --- a/sys/sys.go +++ b/sys/sys.go @@ -6,6 +6,7 @@ package sys import ( _ "github.com/google/syzkaller/sys/fuchsia" _ "github.com/google/syzkaller/sys/linux" + _ "github.com/google/syzkaller/sys/windows" ) // Emitted by Makefile. diff --git a/sys/syz-extract/extract.go b/sys/syz-extract/extract.go index 6820363db..bff00b23f 100644 --- a/sys/syz-extract/extract.go +++ b/sys/syz-extract/extract.go @@ -9,9 +9,11 @@ import ( "fmt" "io/ioutil" "os" + "os/exec" "path/filepath" "runtime" "sort" + "strconv" "strings" "sync" @@ -55,6 +57,7 @@ var oses = map[string]OS{ "linux": new(linux), "android": new(linux), "fuchsia": new(fuchsia), + "windows": new(windows), } func main() { @@ -68,9 +71,6 @@ func main() { if OS == nil { failf("unknown os: %v", *flagOS) } - if *flagSourceDir == "" { - failf("provide path to kernel checkout via -sourcedir flag (or make extract SOURCEDIR)") - } if *flagBuild && *flagBuildDir != "" { failf("-build and -builddir is an invalid combination") } @@ -230,3 +230,35 @@ func processFile(OS OS, arch *Arch, inname string) (map[string]bool, error) { } return undeclared, nil } + +func runBinaryAndParse(bin string, vals []string, undeclared map[string]bool) (map[string]uint64, error) { + out, err := exec.Command(bin).CombinedOutput() + if err != nil { + return nil, fmt.Errorf("failed to run flags binary: %v\n%v", err, string(out)) + } + flagVals := strings.Split(string(out), " ") + if len(out) == 0 { + flagVals = nil + } + if len(flagVals) != len(vals)-len(undeclared) { + return nil, fmt.Errorf("fetched wrong number of values %v != %v - %v\nflagVals: %q\nvals: %q\nundeclared: %q", + len(flagVals), len(vals), len(undeclared), + flagVals, vals, undeclared) + } + res := make(map[string]uint64) + j := 0 + for _, v := range flagVals { + name := vals[j] + j++ + for undeclared[name] { + name = vals[j] + j++ + } + n, err := strconv.ParseUint(v, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse value: %v (%v)", err, v) + } + res[name] = n + } + return res, nil +} diff --git a/sys/syz-extract/fuchsia.go b/sys/syz-extract/fuchsia.go index 1d3405ba8..f3cab132f 100644 --- a/sys/syz-extract/fuchsia.go +++ b/sys/syz-extract/fuchsia.go @@ -9,7 +9,6 @@ import ( "os" "os/exec" "path/filepath" - "strconv" "strings" "github.com/google/syzkaller/pkg/compiler" @@ -18,6 +17,9 @@ import ( type fuchsia struct{} func (*fuchsia) prepare(sourcedir string, build bool, arches []string) error { + if sourcedir == "" { + return fmt.Errorf("provide path to kernel checkout via -sourcedir flag (or make extract SOURCEDIR)") + } return nil } @@ -31,26 +33,9 @@ func (*fuchsia) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]ui return nil, nil, fmt.Errorf("failed to run compiler: %v\n%v", err, string(out)) } defer os.Remove(bin) - - out, err = exec.Command(bin).CombinedOutput() + res, err := runBinaryAndParse(bin, info.Consts, nil) if err != nil { - return nil, nil, fmt.Errorf("failed to run compiled binary: %v\n%v", err, string(out)) - } - - flagVals := strings.Split(string(out), " ") - if len(out) == 0 { - flagVals = nil - } - if len(flagVals) != len(info.Consts) { - return nil, nil, fmt.Errorf("fetched wrong number of values %v, want %v", len(flagVals), len(info.Consts)) - } - res := make(map[string]uint64) - for i, v := range flagVals { - n, err := strconv.ParseUint(v, 10, 64) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse value: %v (%v)", err, v) - } - res[info.Consts[i]] = n + return nil, nil, err } return res, nil, nil } diff --git a/sys/syz-extract/linux.go b/sys/syz-extract/linux.go index 8c38c75ee..7a0a226ef 100644 --- a/sys/syz-extract/linux.go +++ b/sys/syz-extract/linux.go @@ -9,7 +9,6 @@ import ( "os" "os/exec" "regexp" - "strconv" "strings" "time" @@ -21,6 +20,9 @@ import ( type linux struct{} func (*linux) prepare(sourcedir string, build bool, arches []string) error { + if sourcedir == "" { + return fmt.Errorf("provide path to kernel checkout via -sourcedir flag (or make extract SOURCEDIR)") + } if build { // Otherwise out-of-tree build fails. fmt.Printf("make mrproper\n") @@ -110,34 +112,9 @@ func (*linux) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint } defer os.Remove(bin) - out, err = exec.Command(bin).CombinedOutput() + res, err := runBinaryAndParse(bin, vals, undeclared) if err != nil { - return nil, nil, fmt.Errorf("failed to run flags binary: %v\n%v", err, string(out)) - } - - flagVals := strings.Split(string(out), " ") - if len(out) == 0 { - flagVals = nil - } - if len(flagVals) != len(vals)-len(undeclared) { - return nil, nil, fmt.Errorf("fetched wrong number of values %v != %v - %v\nflagVals: %q\nvals: %q\nundeclared: %q", - len(flagVals), len(vals), len(undeclared), - flagVals, vals, undeclared) - } - res := make(map[string]uint64) - j := 0 - for _, v := range flagVals { - name := vals[j] - j++ - for undeclared[name] { - name = vals[j] - j++ - } - n, err := strconv.ParseUint(v, 10, 64) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse value: %v (%v)", err, v) - } - res[name] = n + return nil, nil, err } return res, undeclared, nil } diff --git a/sys/syz-extract/windows.go b/sys/syz-extract/windows.go new file mode 100644 index 000000000..81e3f6c23 --- /dev/null +++ b/sys/syz-extract/windows.go @@ -0,0 +1,94 @@ +// Copyright 2017 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. + +package main + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "strings" + + "github.com/google/syzkaller/pkg/compiler" +) + +type windows struct{} + +func (*windows) prepare(sourcedir string, build bool, arches []string) error { + return nil +} + +func (*windows) prepareArch(arch *Arch) error { + return nil +} + +func (*windows) processFile(arch *Arch, info *compiler.ConstInfo) (map[string]uint64, map[string]bool, error) { + bin, out, err := windowsCompile(arch.sourceDir, info.Consts, info.Includes, info.Incdirs, info.Defines) + if err != nil { + return nil, nil, fmt.Errorf("failed to run compiler: %v\n%v", err, string(out)) + } + defer os.Remove(bin) + res, err := runBinaryAndParse(bin, info.Consts, nil) + if err != nil { + return nil, nil, err + } + return res, nil, nil +} + +func windowsCompile(sourceDir string, vals, includes, incdirs []string, defines map[string]string) (bin string, out []byte, err error) { + includeText := "" + for _, inc := range includes { + includeText += fmt.Sprintf("#include <%v>\n", inc) + } + definesText := "" + for k, v := range defines { + definesText += fmt.Sprintf("#ifndef %v\n#define %v %v\n#endif\n", k, k, v) + } + valsText := "(unsigned long long)" + strings.Join(vals, ", (unsigned long long)") + src := windowsSrc + src = strings.Replace(src, "[[INCLUDES]]", includeText, 1) + src = strings.Replace(src, "[[DEFAULTS]]", definesText, 1) + src = strings.Replace(src, "[[VALS]]", valsText, 1) + binFile, err := ioutil.TempFile("", "") + if err != nil { + return "", nil, fmt.Errorf("failed to create temp file: %v", err) + } + binFile.Close() + + srcFile, err := ioutil.TempFile("", "") + if err != nil { + return "", nil, fmt.Errorf("failed to create temp file: %v", err) + } + srcFile.Close() + os.Remove(srcFile.Name()) + srcName := srcFile.Name() + ".cc" + if err := ioutil.WriteFile(srcName, []byte(src), 0600); err != nil { + return "", nil, fmt.Errorf("failed to write source file: %v", err) + } + defer os.Remove(srcName) + args := []string{"-o", binFile.Name(), srcName} + cmd := exec.Command("cl", args...) + out, err = cmd.CombinedOutput() + if err != nil { + os.Remove(binFile.Name()) + return "", out, err + } + return binFile.Name(), nil, nil +} + +var windowsSrc = ` +#include <stdio.h> +[[INCLUDES]] +[[DEFAULTS]] +int main() { + int i; + unsigned long long vals[] = {[[VALS]]}; + for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) { + if (i != 0) + printf(" "); + printf("%llu", vals[i]); + } + return 0; +} +` diff --git a/sys/syz-sysgen/sysgen.go b/sys/syz-sysgen/sysgen.go index 273bb7d04..e34055f1c 100644 --- a/sys/syz-sysgen/sysgen.go +++ b/sys/syz-sysgen/sysgen.go @@ -36,7 +36,7 @@ func main() { flag.Parse() for OS, archs := range targets.List { - top := ast.ParseGlob(filepath.Join("sys", OS, "*\\.txt"), nil) + top := ast.ParseGlob(filepath.Join("sys", OS, "*.txt"), nil) if top == nil { os.Exit(1) } @@ -67,7 +67,7 @@ func main() { eh := func(pos ast.Pos, msg string) { job.Errors = append(job.Errors, fmt.Sprintf("%v: %v\n", pos, msg)) } - consts := compiler.DeserializeConstsGlob(filepath.Join("sys", OS, "*_"+job.Target.Arch+"\\.const"), eh) + consts := compiler.DeserializeConstsGlob(filepath.Join("sys", OS, "*_"+job.Target.Arch+".const"), eh) if consts == nil { return } diff --git a/sys/targets/targets.go b/sys/targets/targets.go index 8e00b0fa6..3c0011be4 100644 --- a/sys/targets/targets.go +++ b/sys/targets/targets.go @@ -72,6 +72,12 @@ var List = map[string]map[string]*Target{ CArch: []string{"__aarch64__"}, }, }, + "windows": map[string]*Target{ + "amd64": { + PtrSize: 8, + CArch: []string{"_M_X64"}, + }, + }, } type OS struct { @@ -86,6 +92,9 @@ var OSList = map[string]*OS{ "fuchsia": { SyscallNumbers: false, }, + "windows": { + SyscallNumbers: false, + }, } func init() { diff --git a/sys/windows/amd64.go b/sys/windows/amd64.go new file mode 100644 index 000000000..0d6884835 --- /dev/null +++ b/sys/windows/amd64.go @@ -0,0 +1,129 @@ +// AUTOGENERATED FILE +package windows + +import . "github.com/google/syzkaller/prog" + +func init() { + RegisterTarget(&Target{OS: "windows", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) +} + +var resources_amd64 = []*ResourceDesc{ + {Name: "HANDLE", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "intptr", TypeSize: 8}}}, Kind: []string{"HANDLE"}, Values: []uint64{18446744073709551615}}, + {Name: "hFile", Type: &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "intptr", TypeSize: 8}}}, Kind: []string{"HANDLE", "hFile"}, Values: []uint64{18446744073709551615}}, +} + +var structDescs_amd64 = []*KeyedStruct{ + {Key: StructKey{Name: "SECURITY_ATTRIBUTES"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "SECURITY_ATTRIBUTES", TypeSize: 24}, Fields: []Type{ + &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "nLength", TypeSize: 4}}, Buf: "parent"}, + &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 4}}, IsPad: true}, + &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "lpSecurityDescriptor", TypeSize: 8, IsOptional: true}, Type: &StructType{Key: StructKey{Name: "SECURITY_DESCRIPTOR"}}}, + &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "bInheritHandle", TypeSize: 4}}, Kind: 2, RangeEnd: 1}, + &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "pad", TypeSize: 4}}, IsPad: true}, + }}}, + {Key: StructKey{Name: "SECURITY_DESCRIPTOR"}, Desc: &StructDesc{TypeCommon: TypeCommon{TypeName: "SECURITY_DESCRIPTOR", TypeSize: 4}, Fields: []Type{ + &IntType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "int32", FldName: "stub", TypeSize: 4}}}, + }}}, +} + +var syscalls_amd64 = []*Syscall{ + {Name: "CloseHandle", CallName: "CloseHandle", Args: []Type{ + &ResourceType{TypeCommon: TypeCommon{TypeName: "HANDLE", FldName: "hObject", TypeSize: 8}}, + }}, + {ID: 1, Name: "CreateFileA", CallName: "CreateFileA", Args: []Type{ + &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "lpFileName", TypeSize: 8}, Type: &BufferType{TypeCommon: TypeCommon{TypeName: "filename"}, Kind: 3}}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "file_access_rights", FldName: "dwDesiredAccess", TypeSize: 8}}, Vals: []uint64{65536, 131072, 1048576, 262144, 524288, 2, 4, 2032127, 4, 4, 64, 32, 1, 128, 1, 8, 32, 256, 2, 16}}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "file_share_mode", FldName: "dwShareMode", TypeSize: 8}}, Vals: []uint64{4, 1, 2}}, + &PtrType{TypeCommon: TypeCommon{TypeName: "ptr", FldName: "lpSecurityAttributes", TypeSize: 8, IsOptional: true}, Type: &StructType{Key: StructKey{Name: "SECURITY_ATTRIBUTES"}}}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "file_create_disposition", FldName: "dwCreationDisposition", TypeSize: 8}}, Vals: []uint64{2, 1, 4, 3, 5}}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "file_attributes", FldName: "dwFlagsAndAttributes", TypeSize: 8}}, Vals: []uint64{32, 16384, 2, 128, 4096, 1, 4, 256, 33554432, 67108864, 536870912, 1048576, 2097152, 1073741824, 16777216, 268435456, 8388608, 134217728, 2147483648, 0, 262144, 196608, 524288, 65536, 131072}}, + &ResourceType{TypeCommon: TypeCommon{TypeName: "HANDLE", FldName: "hTemplateFile", TypeSize: 8, IsOptional: true}}, + }, Ret: &ResourceType{TypeCommon: TypeCommon{TypeName: "hFile", FldName: "ret", TypeSize: 8, ArgDir: 1}}}, + {ID: 2, Name: "VirtualAlloc", CallName: "VirtualAlloc", Args: []Type{ + &VmaType{TypeCommon: TypeCommon{TypeName: "vma", FldName: "lpAddress", TypeSize: 8}}, + &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "dwSize", TypeSize: 8}}, Buf: "lpAddress"}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "allocation_type", FldName: "flAllocationType", TypeSize: 8}}, Vals: []uint64{4096, 8192, 524288, 16777216, 536870912, 4194304, 1048576, 2097152}}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "protect_flags", FldName: "flProtect", TypeSize: 8}}, Vals: []uint64{16, 32, 64, 128, 1, 2, 4, 8, 1073741824, 1073741824, 256, 512, 1024, 2147483648, 536870912}}, + }}, +} + +var consts_amd64 = []ConstValue{ + {Name: "CREATE_ALWAYS", Value: 2}, + {Name: "CREATE_NEW", Value: 1}, + {Name: "DELETE", Value: 65536}, + {Name: "FILE_ADD_FILE", Value: 2}, + {Name: "FILE_ADD_SUBDIRECTORY", Value: 4}, + {Name: "FILE_ALL_ACCESS", Value: 2032127}, + {Name: "FILE_APPEND_DATA", Value: 4}, + {Name: "FILE_ATTRIBUTE_ARCHIVE", Value: 32}, + {Name: "FILE_ATTRIBUTE_ENCRYPTED", Value: 16384}, + {Name: "FILE_ATTRIBUTE_HIDDEN", Value: 2}, + {Name: "FILE_ATTRIBUTE_NORMAL", Value: 128}, + {Name: "FILE_ATTRIBUTE_OFFLINE", Value: 4096}, + {Name: "FILE_ATTRIBUTE_READONLY", Value: 1}, + {Name: "FILE_ATTRIBUTE_SYSTEM", Value: 4}, + {Name: "FILE_ATTRIBUTE_TEMPORARY", Value: 256}, + {Name: "FILE_CREATE_PIPE_INSTANCE", Value: 4}, + {Name: "FILE_DELETE_CHILD", Value: 64}, + {Name: "FILE_EXECUTE", Value: 32}, + {Name: "FILE_FLAG_BACKUP_SEMANTICS", Value: 33554432}, + {Name: "FILE_FLAG_DELETE_ON_CLOSE", Value: 67108864}, + {Name: "FILE_FLAG_NO_BUFFERING", Value: 536870912}, + {Name: "FILE_FLAG_OPEN_NO_RECALL", Value: 1048576}, + {Name: "FILE_FLAG_OPEN_REPARSE_POINT", Value: 2097152}, + {Name: "FILE_FLAG_OVERLAPPED", Value: 1073741824}, + {Name: "FILE_FLAG_POSIX_SEMANTICS", Value: 16777216}, + {Name: "FILE_FLAG_RANDOM_ACCESS", Value: 268435456}, + {Name: "FILE_FLAG_SEQUENTIAL_SCAN", Value: 134217728}, + {Name: "FILE_FLAG_SESSION_AWARE", Value: 8388608}, + {Name: "FILE_FLAG_WRITE_THROUGH", Value: 2147483648}, + {Name: "FILE_LIST_DIRECTORY", Value: 1}, + {Name: "FILE_READ_ATTRIBUTES", Value: 128}, + {Name: "FILE_READ_DATA", Value: 1}, + {Name: "FILE_READ_EA", Value: 8}, + {Name: "FILE_SHARE_DELETE", Value: 4}, + {Name: "FILE_SHARE_READ", Value: 1}, + {Name: "FILE_SHARE_WRITE", Value: 2}, + {Name: "FILE_TRAVERSE", Value: 32}, + {Name: "FILE_WRITE_ATTRIBUTES", Value: 256}, + {Name: "FILE_WRITE_DATA", Value: 2}, + {Name: "FILE_WRITE_EA", Value: 16}, + {Name: "INVALID_HANDLE_VALUE", Value: 18446744073709551615}, + {Name: "MEM_COMMIT", Value: 4096}, + {Name: "MEM_LARGE_PAGES", Value: 536870912}, + {Name: "MEM_PHYSICAL", Value: 4194304}, + {Name: "MEM_RESERVE", Value: 8192}, + {Name: "MEM_RESET", Value: 524288}, + {Name: "MEM_RESET_UNDO", Value: 16777216}, + {Name: "MEM_TOP_DOWN", Value: 1048576}, + {Name: "MEM_WRITE_WATCH", Value: 2097152}, + {Name: "OPEN_ALWAYS", Value: 4}, + {Name: "OPEN_EXISTING", Value: 3}, + {Name: "PAGE_ENCLAVE_THREAD_CONTROL", Value: 2147483648}, + {Name: "PAGE_ENCLAVE_UNVALIDATED\x00", Value: 536870912}, + {Name: "PAGE_EXECUTE", Value: 16}, + {Name: "PAGE_EXECUTE_READ", Value: 32}, + {Name: "PAGE_EXECUTE_READWRITE", Value: 64}, + {Name: "PAGE_EXECUTE_WRITECOPY", Value: 128}, + {Name: "PAGE_GUARD", Value: 256}, + {Name: "PAGE_NOACCESS", Value: 1}, + {Name: "PAGE_NOCACHE", Value: 512}, + {Name: "PAGE_READONLY", Value: 2}, + {Name: "PAGE_READWRITE", Value: 4}, + {Name: "PAGE_TARGETS_INVALID", Value: 1073741824}, + {Name: "PAGE_TARGETS_NO_UPDATE", Value: 1073741824}, + {Name: "PAGE_WRITECOMBINE", Value: 1024}, + {Name: "PAGE_WRITECOPY", Value: 8}, + {Name: "READ_CONTROL", Value: 131072}, + {Name: "SECURITY_ANONYMOUS"}, + {Name: "SECURITY_CONTEXT_TRACKING", Value: 262144}, + {Name: "SECURITY_DELEGATION", Value: 196608}, + {Name: "SECURITY_EFFECTIVE_ONLY", Value: 524288}, + {Name: "SECURITY_IDENTIFICATION", Value: 65536}, + {Name: "SECURITY_IMPERSONATION", Value: 131072}, + {Name: "SYNCHRONIZE", Value: 1048576}, + {Name: "TRUNCATE_EXISTING", Value: 5}, + {Name: "WRITE_DAC", Value: 262144}, + {Name: "WRITE_OWNER", Value: 524288}, +} + +const revision_amd64 = "5abfe477fc941d0acacdeae7934602a90c22d5bc" diff --git a/sys/windows/init.go b/sys/windows/init.go new file mode 100644 index 000000000..8e3761024 --- /dev/null +++ b/sys/windows/init.go @@ -0,0 +1,61 @@ +// Copyright 2017 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. + +package windows + +import ( + "github.com/google/syzkaller/prog" +) + +func initTarget(target *prog.Target) { + arch := &arch{ + virtualAllocSyscall: target.SyscallMap["VirtualAlloc"], + MEM_COMMIT: target.ConstMap["MEM_COMMIT"], + MEM_RESERVE: target.ConstMap["MEM_RESERVE"], + PAGE_EXECUTE_READWRITE: target.ConstMap["PAGE_EXECUTE_READWRITE"], + } + + target.PageSize = pageSize + target.DataOffset = dataOffset + target.MmapSyscall = arch.virtualAllocSyscall + target.MakeMmap = arch.makeMmap + target.AnalyzeMmap = arch.analyzeMmap +} + +const ( + // TODO(dvyukov): what should we do about 4k vs 64k? + pageSize = 4 << 10 + dataOffset = 512 << 20 +) + +type arch struct { + virtualAllocSyscall *prog.Syscall + + MEM_COMMIT uint64 + MEM_RESERVE uint64 + PAGE_EXECUTE_READWRITE uint64 +} + +func (arch *arch) makeMmap(start, npages uint64) *prog.Call { + meta := arch.virtualAllocSyscall + return &prog.Call{ + Meta: meta, + Args: []prog.Arg{ + prog.MakePointerArg(meta.Args[0], start, 0, npages, nil), + prog.MakeConstArg(meta.Args[1], npages*pageSize), + prog.MakeConstArg(meta.Args[2], arch.MEM_COMMIT|arch.MEM_RESERVE), + prog.MakeConstArg(meta.Args[3], arch.PAGE_EXECUTE_READWRITE), + }, + Ret: prog.MakeReturnArg(meta.Ret), + } +} + +func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) { + switch c.Meta.Name { + case "VirtualAlloc": + npages = c.Args[1].(*prog.ConstArg).Val / pageSize + start = c.Args[0].(*prog.PointerArg).PageIndex + mapped = true + } + return +} diff --git a/sys/windows/sys.txt b/sys/windows/sys.txt new file mode 100644 index 000000000..077a499db --- /dev/null +++ b/sys/windows/sys.txt @@ -0,0 +1,31 @@ +# Copyright 2017 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 <windows.h> + +resource HANDLE[intptr]: INVALID_HANDLE_VALUE +resource hFile[HANDLE] + +CloseHandle(hObject HANDLE) +CreateFileA(lpFileName ptr[in, filename], dwDesiredAccess flags[file_access_rights], dwShareMode flags[file_share_mode], lpSecurityAttributes ptr[in, SECURITY_ATTRIBUTES, opt], dwCreationDisposition flags[file_create_disposition], dwFlagsAndAttributes flags[file_attributes], hTemplateFile HANDLE[opt]) hFile +VirtualAlloc(lpAddress vma, dwSize len[lpAddress], flAllocationType flags[allocation_type], flProtect flags[protect_flags]) + +SECURITY_ATTRIBUTES { + nLength len[parent, int32] + lpSecurityDescriptor ptr[in, SECURITY_DESCRIPTOR, opt] +# TODO: at this point we probably do need the BOOL type. + bInheritHandle int32[0:1] +} + +# TODO: describe +SECURITY_DESCRIPTOR { + stub int32 +} + +access_rights = DELETE, READ_CONTROL, SYNCHRONIZE, WRITE_DAC, WRITE_OWNER +file_access_rights = DELETE, READ_CONTROL, SYNCHRONIZE, WRITE_DAC, WRITE_OWNER, FILE_ADD_FILE, FILE_ADD_SUBDIRECTORY, FILE_ALL_ACCESS, FILE_APPEND_DATA, FILE_CREATE_PIPE_INSTANCE, FILE_DELETE_CHILD, FILE_EXECUTE, FILE_LIST_DIRECTORY, FILE_READ_ATTRIBUTES, FILE_READ_DATA, FILE_READ_EA, FILE_TRAVERSE, FILE_WRITE_ATTRIBUTES, FILE_WRITE_DATA, FILE_WRITE_EA +file_share_mode = FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE +file_create_disposition = CREATE_ALWAYS, CREATE_NEW, OPEN_ALWAYS, OPEN_EXISTING, TRUNCATE_EXISTING +file_attributes = FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ENCRYPTED, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_OFFLINE, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_TEMPORARY, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_DELETE_ON_CLOSE, FILE_FLAG_NO_BUFFERING, FILE_FLAG_OPEN_NO_RECALL, FILE_FLAG_OPEN_REPARSE_POINT, FILE_FLAG_OVERLAPPED, FILE_FLAG_POSIX_SEMANTICS, FILE_FLAG_RANDOM_ACCESS, FILE_FLAG_SESSION_AWARE, FILE_FLAG_SEQUENTIAL_SCAN, FILE_FLAG_WRITE_THROUGH, SECURITY_ANONYMOUS, SECURITY_CONTEXT_TRACKING, SECURITY_DELEGATION, SECURITY_EFFECTIVE_ONLY, SECURITY_IDENTIFICATION, SECURITY_IMPERSONATION +allocation_type = MEM_COMMIT, MEM_RESERVE, MEM_RESET, MEM_RESET_UNDO, MEM_LARGE_PAGES, MEM_PHYSICAL, MEM_TOP_DOWN, MEM_WRITE_WATCH +protect_flags = PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY, PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY, PAGE_TARGETS_INVALID, PAGE_TARGETS_NO_UPDATE, PAGE_GUARD, PAGE_NOCACHE, PAGE_WRITECOMBINE, PAGE_ENCLAVE_THREAD_CONTROL, PAGE_ENCLAVE_UNVALIDATED
\ No newline at end of file diff --git a/sys/windows/sys_amd64.const b/sys/windows/sys_amd64.const Binary files differnew file mode 100644 index 000000000..d20c17bf3 --- /dev/null +++ b/sys/windows/sys_amd64.const |
