diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common.h | 17 | ||||
| -rw-r--r-- | executor/common_linux.h | 12 | ||||
| -rw-r--r-- | executor/executor.cc | 1 | ||||
| -rw-r--r-- | executor/executor_linux.h | 11 |
4 files changed, 40 insertions, 1 deletions
diff --git a/executor/common.h b/executor/common.h index 74e75d33b..ddb33bec7 100644 --- a/executor/common.h +++ b/executor/common.h @@ -57,6 +57,11 @@ NORETURN void doexit(int status) for (;;) { } } +NORETURN void doexit_thread(int status) +{ + // For BSD systems, _exit seems to do exactly what's needed. + doexit(status); +} #endif #if SYZ_EXECUTOR || SYZ_MULTI_PROC || SYZ_REPEAT && SYZ_CGROUPS || \ @@ -76,6 +81,7 @@ static unsigned long long procid; #include <sys/syscall.h> #endif +static __thread int clone_ongoing; static __thread int skip_segv; static __thread jmp_buf segv_env; @@ -95,6 +101,17 @@ static void segv_handler(int sig, siginfo_t* info, void* ctx) // 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. + + if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) { + // During clone, we always exit on a SEGV. If we do not, then + // it might prevent us from running child-specific code. E.g. + // if an invalid stack is passed to the clone() call, then it + // will trigger a seg fault, which in turn causes the child to + // jump over the NONFAILING macro and continue execution in + // parallel with the parent. + doexit_thread(sig); + } + uintptr_t addr = (uintptr_t)info->si_addr; const uintptr_t prog_start = 1 << 20; const uintptr_t prog_end = 100 << 20; diff --git a/executor/common_linux.h b/executor/common_linux.h index 520c13506..88c129f85 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -5226,8 +5226,12 @@ static long syz_80211_join_ibss(volatile long a0, volatile long a1, volatile lon static long handle_clone_ret(long ret) { - if (ret != 0) + if (ret != 0) { +#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV + __atomic_store_n(&clone_ongoing, 0, __ATOMIC_RELAXED); +#endif return ret; + } // Exit if we're in the child process - not all kernels provide the proper means // to prevent fork-bombs. // But first sleep for some time. This will hopefully foster IPC fuzzing. @@ -5247,6 +5251,9 @@ static long syz_clone(volatile long flags, volatile long stack, volatile long st { // ABI requires 16-byte stack alignment. long sp = (stack + stack_len) & ~15; +#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV + __atomic_store_n(&clone_ongoing, 1, __ATOMIC_RELAXED); +#endif // Clear the CLONE_VM flag. Otherwise it'll very likely corrupt syz-executor. long ret = (long)syscall(__NR_clone, flags & ~CLONE_VM, sp, ptid, ctid, tls); return handle_clone_ret(ret); @@ -5270,6 +5277,9 @@ static long syz_clone3(volatile long a0, volatile long a1) // As in syz_clone, clear the CLONE_VM flag. Flags are in the first 8-byte integer field. uint64* flags = (uint64*)&clone_args; *flags &= ~CLONE_VM; +#if SYZ_EXECUTOR || SYZ_HANDLE_SEGV + __atomic_store_n(&clone_ongoing, 1, __ATOMIC_RELAXED); +#endif return handle_clone_ret((long)syscall(__NR_clone3, &clone_args, copy_size)); } diff --git a/executor/executor.cc b/executor/executor.cc index 923fccc63..28ab72206 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -90,6 +90,7 @@ static NORETURN PRINTF(2, 3) void failmsg(const char* err, const char* msg, ...) // Just exit (e.g. due to temporal ENOMEM error). static NORETURN PRINTF(1, 2) void exitf(const char* msg, ...); static NORETURN void doexit(int status); +static NORETURN void doexit_thread(int status); // Print debug output that is visible when running syz-manager/execprog with -debug flag. // Debug output is supposed to be relatively high-level (syscalls executed, return values, timing, etc) diff --git a/executor/executor_linux.h b/executor/executor_linux.h index 8666d929b..3f422f6f2 100644 --- a/executor/executor_linux.h +++ b/executor/executor_linux.h @@ -224,6 +224,17 @@ NORETURN void doexit(int status) } } +// If we need to kill just a single thread (e.g. after cloning), exit_group is not +// the right choice - it will kill all threads, which might eventually lead to +// unnecessary SYZFAIL errors. +NORETURN void doexit_thread(int status) +{ + volatile unsigned i; + syscall(__NR_exit, status); + for (i = 0;; i++) { + } +} + #define SYZ_HAVE_FEATURES 1 static feature_t features[] = { {"leak", setup_leak}, |
