aboutsummaryrefslogtreecommitdiffstats
path: root/executor/common_linux.h
diff options
context:
space:
mode:
Diffstat (limited to 'executor/common_linux.h')
-rw-r--r--executor/common_linux.h59
1 files changed, 59 insertions, 0 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 479c229dc..520c13506 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -5215,3 +5215,62 @@ static long syz_80211_join_ibss(volatile long a0, volatile long a1, volatile lon
}
#endif
+
+#if SYZ_EXECUTOR || __NR_syz_clone || __NR_syz_clone3
+#if SYZ_EXECUTOR
+// The slowdown multiplier is already taken into account.
+#define USLEEP_FORKED_CHILD (3 * syscall_timeout_ms * 1000)
+#else
+#define USLEEP_FORKED_CHILD (3 * /*{{{BASE_CALL_TIMEOUT_MS}}}*/ *1000)
+#endif
+
+static long handle_clone_ret(long ret)
+{
+ if (ret != 0)
+ 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.
+ usleep(USLEEP_FORKED_CHILD);
+ // Note that exit_group is a bad choice here because if we created just a thread, then
+ // the whole process will be killed. A plain exit will work fine in any case.
+ syscall(__NR_exit, 0);
+ while (1) {
+ }
+}
+#endif
+
+#if SYZ_EXECUTOR || __NR_syz_clone
+// syz_clone is mostly needed on kernels which do not suport clone3.
+static long syz_clone(volatile long flags, volatile long stack, volatile long stack_len,
+ volatile long ptid, volatile long ctid, volatile long tls)
+{
+ // ABI requires 16-byte stack alignment.
+ long sp = (stack + stack_len) & ~15;
+ // 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);
+}
+#endif
+
+#if SYZ_EXECUTOR || __NR_syz_clone3
+#include <linux/sched.h>
+#include <sched.h>
+
+#define MAX_CLONE_ARGS_BYTES 256
+static long syz_clone3(volatile long a0, volatile long a1)
+{
+ unsigned long copy_size = a1;
+ if (copy_size < sizeof(uint64) || copy_size > MAX_CLONE_ARGS_BYTES)
+ return -1;
+ // The structure may have different sizes on different kernel versions, so copy it as raw bytes.
+ char clone_args[MAX_CLONE_ARGS_BYTES];
+ memcpy(&clone_args, (void*)a0, copy_size);
+
+ // 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;
+ return handle_clone_ret((long)syscall(__NR_clone3, &clone_args, copy_size));
+}
+
+#endif