aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-09-24 11:13:37 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-09-25 15:19:06 +0200
commitaf442a22d956464e7df703b290fa49d78dda3dfa (patch)
treeb50403630f29373cfb711a711fbfd24d632ce2ba
parent255e8b5e54e93fc77302a546dbb7a932412d1bde (diff)
executor, sys/windows: initial windows support
-rw-r--r--docs/windows.md18
-rw-r--r--executor/common.h67
-rw-r--r--executor/common_fuchsia.h66
-rw-r--r--executor/common_linux.h65
-rw-r--r--executor/common_windows.h50
-rw-r--r--executor/executor.h22
-rw-r--r--executor/executor_fuchsia.cc66
-rw-r--r--executor/executor_linux.cc53
-rw-r--r--executor/executor_linux.h66
-rw-r--r--executor/executor_posix.h82
-rw-r--r--executor/executor_windows.cc85
-rw-r--r--executor/executor_windows.h74
-rw-r--r--executor/syscalls_windows.h14
-rw-r--r--pkg/ast/scanner.go3
-rw-r--r--pkg/csource/common.go113
-rw-r--r--pkg/csource/csource_test.go6
-rw-r--r--sys/sys.go1
-rw-r--r--sys/syz-extract/extract.go38
-rw-r--r--sys/syz-extract/fuchsia.go25
-rw-r--r--sys/syz-extract/linux.go33
-rw-r--r--sys/syz-extract/windows.go94
-rw-r--r--sys/syz-sysgen/sysgen.go4
-rw-r--r--sys/targets/targets.go9
-rw-r--r--sys/windows/amd64.go129
-rw-r--r--sys/windows/init.go61
-rw-r--r--sys/windows/sys.txt31
-rw-r--r--sys/windows/sys_amd64.constbin0 -> 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
new file mode 100644
index 000000000..d20c17bf3
--- /dev/null
+++ b/sys/windows/sys_amd64.const
Binary files differ