aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/common.h17
-rw-r--r--executor/common_linux.h12
-rw-r--r--executor/executor.cc1
-rw-r--r--executor/executor_linux.h11
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},