aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource/linux_common.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-07-20 20:26:05 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-07-24 12:04:27 +0200
commit9fe4bdc5f1037a409e82299f36117030114c7b94 (patch)
treed3d73c1f69ded8152436be47684a07baa0e7f6ec /pkg/csource/linux_common.go
parentdb7957bc09bf5715d33e4c56b8614579aa94000a (diff)
executor: overhaul
Make as much code as possible shared between all OSes. In particular main is now common across all OSes. Make more code shared between executor and csource (in particular, loop function and threaded execution logic). Also make loop and threaded logic shared across all OSes. Make more posix/unix code shared across OSes (e.g. signal handling, pthread creation, etc). Plus other changes along similar lines. Also support test OS in executor (based on portable posix) and add 4 arches that cover all execution modes (fork server/no fork server, shmem/no shmem). This change paves way for testing of executor code and allows to preserve consistency across OSes and executor/csource.
Diffstat (limited to 'pkg/csource/linux_common.go')
-rw-r--r--pkg/csource/linux_common.go3143
1 files changed, 0 insertions, 3143 deletions
diff --git a/pkg/csource/linux_common.go b/pkg/csource/linux_common.go
deleted file mode 100644
index 32b65bb70..000000000
--- a/pkg/csource/linux_common.go
+++ /dev/null
@@ -1,3143 +0,0 @@
-// AUTOGENERATED FROM executor/common_linux.h
-
-package csource
-
-var commonHeaderLinux = `
-
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <endian.h>
-#include <stdio.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE)
-#include <linux/futex.h>
-#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 <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
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR))
-#include <dirent.h>
-#include <sys/mount.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE)
-#include <errno.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) || defined(SYZ_SANDBOX_NAMESPACE) || \
- defined(SYZ_ENABLE_CGROUPS)
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_SETUID)
-#include <grp.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NAMESPACE)
-#include <linux/capability.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_ENABLE_NETDEV)
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/if_tun.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <net/if_arp.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE)
-#include <linux/net.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION)
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <sys/stat.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_open_dev) || defined(__NR_syz_open_procfs)
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_open_pts)
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_kvm_setup_cpu)
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/kvm.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_init_net_socket)
-#include <fcntl.h>
-#include <sched.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_genetlink_get_family_id)
-#include <errno.h>
-#include <linux/genetlink.h>
-#include <linux/netlink.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
-#include <sys/mount.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_mount_image) || defined(__NR_syz_read_part_table)
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/loop.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
- defined(SYZ_USE_TMP_DIR) || defined(SYZ_HANDLE_SEGV) || defined(SYZ_TUN_ENABLE) || \
- defined(SYZ_SANDBOX_NAMESPACE) || defined(SYZ_SANDBOX_SETUID) || \
- defined(SYZ_SANDBOX_NONE) || defined(SYZ_FAULT_INJECTION) || \
- defined(__NR_syz_kvm_setup_cpu) || defined(__NR_syz_init_net_socket) && (defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE))
-__attribute__((noreturn)) static void doexit(int status)
-{
- volatile unsigned i;
- syscall(__NR_exit_group, status);
- for (i = 0;; i++) {
- }
-}
-#endif
-
-
-
-#include <stdint.h>
-#include <string.h>
-#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_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_FAULT_INJECTION) || \
- defined(__NR_syz_kvm_setup_cpu) || defined(__NR_syz_init_net_socket) || \
- defined(__NR_syz_mmap)
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
-#include <stdlib.h>
-#include <sys/stat.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_HANDLE_SEGV)
-#include <setjmp.h>
-#include <signal.h>
-#include <string.h>
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG)
-#include <stdarg.h>
-#include <stdio.h>
-#endif
-
-#if defined(SYZ_EXECUTOR)
-#define exit vsnprintf
-#define _exit vsnprintf
-
-typedef unsigned long long uint64;
-typedef unsigned int uint32;
-typedef unsigned short uint16;
-typedef unsigned char uint8;
-
-#ifdef SYZ_EXECUTOR
-const int kInPipeFd = 250;
-const int kOutPipeFd = 251;
-#endif
-
-#if defined(__GNUC__)
-#define SYSCALLAPI
-#define NORETURN __attribute__((noreturn))
-#define ALIGNED(N) __attribute__((aligned(N)))
-#define PRINTF __attribute__((format(printf, 1, 2)))
-#else
-#define SYSCALLAPI WINAPI
-#define NORETURN __declspec(noreturn)
-#define ALIGNED(N) __declspec(align(N))
-#define PRINTF
-#endif
-
-typedef long(SYSCALLAPI* syscall_t)(long, long, long, long, long, long, long, long, long);
-
-struct call_t {
- const char* name;
- int sys_nr;
- syscall_t call;
-};
-
-#endif
-
-#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_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_FAULT_INJECTION) || \
- defined(__NR_syz_kvm_setup_cpu) || defined(__NR_syz_mmap)
-const int kFailStatus = 67;
-const int kRetryStatus = 69;
-#endif
-
-#if defined(SYZ_EXECUTOR)
-const int kErrorStatus = 68;
-#endif
-
-#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_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(__NR_syz_kvm_setup_cpu) || \
- defined(__NR_syz_init_net_socket) && \
- (defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE)) || \
- defined(__NR_syz_mmap)
-NORETURN PRINTF static void fail(const char* msg, ...)
-{
- int e = errno;
- va_list args;
- va_start(args, msg);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, " (errno %d)\n", e);
- doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR)
-NORETURN PRINTF static void error(const char* msg, ...)
-{
- va_list args;
- va_start(args, msg);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, "\n");
- doexit(kErrorStatus);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR)) || defined(SYZ_FAULT_INJECTION)
-NORETURN PRINTF static void exitf(const char* msg, ...)
-{
- int e = errno;
- va_list args;
- va_start(args, msg);
- vfprintf(stderr, msg, args);
- va_end(args);
- fprintf(stderr, " (errno %d)\n", e);
- doexit(kRetryStatus);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_DEBUG)
-static int flag_debug;
-
-PRINTF static void debug(const char* msg, ...)
-{
- if (!flag_debug)
- return;
- va_list args;
- va_start(args, msg);
- vfprintf(stderr, msg, args);
- va_end(args);
- fflush(stderr);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_BITMASKS)
-#define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1)
-
-#define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, (bf_len)) << (bf_off))
-
-#define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \
- if ((bf_off) == 0 && (bf_len) == 0) { \
- *(type*)(addr) = (type)(val); \
- } else { \
- type new_val = *(type*)(addr); \
- new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \
- new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \
- *(type*)(addr) = new_val; \
- }
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_CHECKSUMS)
-struct csum_inet {
- uint32 acc;
-};
-
-static void csum_inet_init(struct csum_inet* csum)
-{
- csum->acc = 0;
-}
-
-static void csum_inet_update(struct csum_inet* csum, const uint8* data, size_t length)
-{
- if (length == 0)
- return;
-
- size_t i;
- for (i = 0; i < length - 1; i += 2)
- csum->acc += *(uint16*)&data[i];
-
- if (length & 1)
- csum->acc += (uint16)data[length - 1];
-
- while (csum->acc > 0xffff)
- csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
-}
-
-static uint16 csum_inet_digest(struct csum_inet* csum)
-{
- return ~csum->acc;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR)
-struct thread_t;
-void cover_reset(thread_t* th);
-#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", (void*)addr);
- _longjmp(segv_env, 1);
- }
- debug("SIGSEGV on %p, exiting\n", (void*)addr);
- doexit(sig);
-}
-
-static void install_segv_handler()
-{
- struct sigaction sa;
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_IGN;
- syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
- syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_sigaction = segv_handler;
- sa.sa_flags = SA_NODEFER | SA_SIGINFO;
- 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 current_time_ms()
-{
- struct timespec ts;
-
- if (clock_gettime(CLOCK_MONOTONIC, &ts))
- fail("clock_gettime failed");
- return (uint64)ts.tv_sec * 1000 + (uint64)ts.tv_nsec / 1000000;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR)
-static void sleep_ms(uint64 ms)
-{
- usleep(ms * 1000);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
-static void use_temporary_dir()
-{
- char tmpdir_template[] = "./syzkaller.XXXXXX";
- char* tmpdir = mkdtemp(tmpdir_template);
- if (!tmpdir)
- fail("failed to mkdtemp");
- if (chmod(tmpdir, 0777))
- fail("failed to chmod");
- if (chdir(tmpdir))
- fail("failed to chdir");
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_ENABLE_NETDEV)
-static void vsnprintf_check(char* str, size_t size, const char* format, va_list args)
-{
- int rv;
-
- rv = vsnprintf(str, size, format, args);
- if (rv < 0)
- fail("tun: snprintf failed");
- if ((size_t)rv >= size)
- fail("tun: string '%s...' doesn't fit into buffer", str);
-}
-
-#define COMMAND_MAX_LEN 128
-#define PATH_PREFIX "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin "
-#define PATH_PREFIX_LEN (sizeof(PATH_PREFIX) - 1)
-
-static void execute_command(bool panic, const char* format, ...)
-{
- va_list args;
- char command[PATH_PREFIX_LEN + COMMAND_MAX_LEN];
- int rv;
-
- va_start(args, format);
- memcpy(command, PATH_PREFIX, PATH_PREFIX_LEN);
- vsnprintf_check(command + PATH_PREFIX_LEN, COMMAND_MAX_LEN, format, args);
- va_end(args);
- rv = system(command);
- if (rv) {
- if (panic)
- fail("command '%s' failed: %d", &command[0], rv);
- debug("command '%s': %d\n", &command[0], rv);
- }
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE)
-static int tunfd = -1;
-static int tun_frags_enabled;
-
-#define SYZ_TUN_MAX_PACKET_SIZE 1000
-
-#define TUN_IFACE "syz_tun"
-
-#define LOCAL_MAC "aa:aa:aa:aa:aa:aa"
-#define REMOTE_MAC "aa:aa:aa:aa:aa:bb"
-
-#define LOCAL_IPV4 "172.20.20.170"
-#define REMOTE_IPV4 "172.20.20.187"
-
-#define LOCAL_IPV6 "fe80::aa"
-#define REMOTE_IPV6 "fe80::bb"
-
-#ifndef IFF_NAPI
-#define IFF_NAPI 0x0010
-#endif
-#ifndef IFF_NAPI_FRAGS
-#define IFF_NAPI_FRAGS 0x0020
-#endif
-
-#ifdef SYZ_EXECUTOR
-extern bool flag_enable_tun;
-#endif
-
-static void initialize_tun(void)
-{
-#ifdef SYZ_EXECUTOR
- if (!flag_enable_tun)
- return;
-#endif
- tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
- if (tunfd == -1) {
-#ifdef SYZ_EXECUTOR
- fail("tun: can't open /dev/net/tun\n");
-#else
- printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
- printf("otherwise fuzzing or reproducing might not work as intended\n");
- return;
-#endif
- }
- const int kTunFd = 252;
- if (dup2(tunfd, kTunFd) < 0)
- fail("dup2(tunfd, kTunFd) failed");
- close(tunfd);
- tunfd = kTunFd;
-
- struct ifreq ifr;
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
- if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
- fail("tun: ioctl(TUNSETIFF) failed");
- }
- if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
- fail("tun: ioctl(TUNGETIFF) failed");
- tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
- debug("tun_frags_enabled=%d\n", tun_frags_enabled);
-
- execute_command(0, "sysctl -w net.ipv6.conf.%s.accept_dad=0", TUN_IFACE);
-
- execute_command(0, "sysctl -w net.ipv6.conf.%s.router_solicitations=0", TUN_IFACE);
-
- execute_command(1, "ip link set dev %s address %s", TUN_IFACE, LOCAL_MAC);
- execute_command(1, "ip addr add %s/24 dev %s", LOCAL_IPV4, TUN_IFACE);
- execute_command(1, "ip neigh add %s lladdr %s dev %s nud permanent",
- REMOTE_IPV4, REMOTE_MAC, TUN_IFACE);
- execute_command(0, "ip -6 addr add %s/120 dev %s", LOCAL_IPV6, TUN_IFACE);
- execute_command(0, "ip -6 neigh add %s lladdr %s dev %s nud permanent",
- REMOTE_IPV6, REMOTE_MAC, TUN_IFACE);
- execute_command(1, "ip link set dev %s up", TUN_IFACE);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_NETDEV)
-
-#define DEV_IPV4 "172.20.20.%d"
-#define DEV_IPV6 "fe80::%02hx"
-#define DEV_MAC "aa:aa:aa:aa:aa:%02hx"
-
-static void snprintf_check(char* str, size_t size, const char* format, ...)
-{
- va_list args;
-
- va_start(args, format);
- vsnprintf_check(str, size, format, args);
- va_end(args);
-}
-
-#ifdef SYZ_EXECUTOR
-extern bool flag_enable_net_dev;
-#endif
-
-static void initialize_netdevices(void)
-{
-#ifdef SYZ_EXECUTOR
- if (!flag_enable_net_dev)
- return;
-#endif
- unsigned i;
- const char* devtypes[] = {"ip6gretap", "bridge", "vcan", "bond", "team"};
- const char* devnames[] = {"lo", "sit0", "bridge0", "vcan0", "tunl0",
- "gre0", "gretap0", "ip_vti0", "ip6_vti0",
- "ip6tnl0", "ip6gre0", "ip6gretap0",
- "erspan0", "bond0", "veth0", "veth1", "team0",
- "veth0_to_bridge", "veth1_to_bridge",
- "veth0_to_bond", "veth1_to_bond",
- "veth0_to_team", "veth1_to_team"};
- const char* devmasters[] = {"bridge", "bond", "team"};
-
- for (i = 0; i < sizeof(devtypes) / (sizeof(devtypes[0])); i++)
- execute_command(0, "ip link add dev %s0 type %s", devtypes[i], devtypes[i]);
- execute_command(0, "ip link add type veth");
-
- for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
- execute_command(0, "ip link add name %s_slave_0 type veth peer name veth0_to_%s", devmasters[i], devmasters[i]);
- execute_command(0, "ip link add name %s_slave_1 type veth peer name veth1_to_%s", devmasters[i], devmasters[i]);
- execute_command(0, "ip link set %s_slave_0 master %s0", devmasters[i], devmasters[i]);
- execute_command(0, "ip link set %s_slave_1 master %s0", devmasters[i], devmasters[i]);
- execute_command(0, "ip link set veth0_to_%s up", devmasters[i]);
- execute_command(0, "ip link set veth1_to_%s up", devmasters[i]);
- }
- execute_command(0, "ip link set bridge_slave_0 up");
- execute_command(0, "ip link set bridge_slave_1 up");
-
- for (i = 0; i < sizeof(devnames) / (sizeof(devnames[0])); i++) {
- char addr[32];
- snprintf_check(addr, sizeof(addr), DEV_IPV4, i + 10);
- execute_command(0, "ip -4 addr add %s/24 dev %s", addr, devnames[i]);
- snprintf_check(addr, sizeof(addr), DEV_IPV6, i + 10);
- execute_command(0, "ip -6 addr add %s/120 dev %s", addr, devnames[i]);
- snprintf_check(addr, sizeof(addr), DEV_MAC, i + 10);
- execute_command(0, "ip link set dev %s address %s", devnames[i], addr);
- execute_command(0, "ip link set dev %s up", devnames[i]);
- }
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_extract_tcp_res) || defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)))
-static int read_tun(char* data, int size)
-{
- if (tunfd < 0)
- return -1;
-
- int rv = read(tunfd, data, size);
- if (rv < 0) {
- if (errno == EAGAIN)
- return -1;
- if (errno == EBADFD)
- return -1;
- fail("tun: read failed with %d", rv);
- }
- return rv;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_DEBUG) && defined(SYZ_TUN_ENABLE) && (defined(__NR_syz_emit_ethernet) || defined(__NR_syz_extract_tcp_res)))
-static void debug_dump_data(const char* data, int length)
-{
- int i;
- for (i = 0; i < length; i++) {
- debug("%02x ", data[i] & 0xff);
- if (i % 16 == 15)
- debug("\n");
- }
- if (i % 16 != 0)
- debug("\n");
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(__NR_syz_emit_ethernet) && defined(SYZ_TUN_ENABLE))
-#define MAX_FRAGS 4
-struct vnet_fragmentation {
- uint32 full;
- uint32 count;
- uint32 frags[MAX_FRAGS];
-};
-
-static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1, uintptr_t a2)
-{
- if (tunfd < 0)
- return (uintptr_t)-1;
-
- uint32 length = a0;
- char* data = (char*)a1;
- debug_dump_data(data, length);
-
- struct vnet_fragmentation* frags = (struct vnet_fragmentation*)a2;
- struct iovec vecs[MAX_FRAGS + 1];
- uint32 nfrags = 0;
- if (!tun_frags_enabled || frags == NULL) {
- vecs[nfrags].iov_base = data;
- vecs[nfrags].iov_len = length;
- nfrags++;
- } else {
- bool full = true;
- uint32 i, count = 0;
- NONFAILING(full = frags->full);
- NONFAILING(count = frags->count);
- if (count > MAX_FRAGS)
- count = MAX_FRAGS;
- for (i = 0; i < count && length != 0; i++) {
- uint32 size = 0;
- NONFAILING(size = frags->frags[i]);
- if (size > length)
- size = length;
- vecs[nfrags].iov_base = data;
- vecs[nfrags].iov_len = size;
- nfrags++;
- data += size;
- length -= size;
- }
- if (length != 0 && (full || nfrags == 0)) {
- vecs[nfrags].iov_base = data;
- vecs[nfrags].iov_len = length;
- nfrags++;
- }
- }
- return writev(tunfd, vecs, nfrags);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_TUN_ENABLE))
-static void flush_tun()
-{
- char data[SYZ_TUN_MAX_PACKET_SIZE];
- while (read_tun(&data[0], sizeof(data)) != -1)
- ;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(__NR_syz_extract_tcp_res) && defined(SYZ_TUN_ENABLE))
-#ifndef __ANDROID__
-struct ipv6hdr {
- __u8 priority : 4,
- version : 4;
- __u8 flow_lbl[3];
-
- __be16 payload_len;
- __u8 nexthdr;
- __u8 hop_limit;
-
- struct in6_addr saddr;
- struct in6_addr daddr;
-};
-#endif
-
-struct tcp_resources {
- uint32 seq;
- uint32 ack;
-};
-
-static uintptr_t syz_extract_tcp_res(uintptr_t a0, uintptr_t a1, uintptr_t a2)
-{
-
- if (tunfd < 0)
- return (uintptr_t)-1;
-
- char data[SYZ_TUN_MAX_PACKET_SIZE];
- int rv = read_tun(&data[0], sizeof(data));
- if (rv == -1)
- return (uintptr_t)-1;
- size_t length = rv;
- debug_dump_data(data, length);
-
- struct tcphdr* tcphdr;
-
- if (length < sizeof(struct ethhdr))
- return (uintptr_t)-1;
- struct ethhdr* ethhdr = (struct ethhdr*)&data[0];
-
- if (ethhdr->h_proto == htons(ETH_P_IP)) {
- if (length < sizeof(struct ethhdr) + sizeof(struct iphdr))
- return (uintptr_t)-1;
- struct iphdr* iphdr = (struct iphdr*)&data[sizeof(struct ethhdr)];
- if (iphdr->protocol != IPPROTO_TCP)
- return (uintptr_t)-1;
- if (length < sizeof(struct ethhdr) + iphdr->ihl * 4 + sizeof(struct tcphdr))
- return (uintptr_t)-1;
- tcphdr = (struct tcphdr*)&data[sizeof(struct ethhdr) + iphdr->ihl * 4];
- } else {
- if (length < sizeof(struct ethhdr) + sizeof(struct ipv6hdr))
- return (uintptr_t)-1;
- struct ipv6hdr* ipv6hdr = (struct ipv6hdr*)&data[sizeof(struct ethhdr)];
- if (ipv6hdr->nexthdr != IPPROTO_TCP)
- return (uintptr_t)-1;
- if (length < sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + sizeof(struct tcphdr))
- return (uintptr_t)-1;
- tcphdr = (struct tcphdr*)&data[sizeof(struct ethhdr) + sizeof(struct ipv6hdr)];
- }
-
- struct tcp_resources* res = (struct tcp_resources*)a0;
- NONFAILING(res->seq = htonl((ntohl(tcphdr->seq) + (uint32)a1)));
- NONFAILING(res->ack = htonl((ntohl(tcphdr->ack_seq) + (uint32)a2)));
-
- debug("extracted seq: %08x\n", res->seq);
- debug("extracted ack: %08x\n", res->ack);
-
- return 0;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_open_dev)
-static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2)
-{
- if (a0 == 0xc || a0 == 0xb) {
- char buf[128];
- sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8)a1, (uint8)a2);
- return open(buf, O_RDWR, 0);
- } else {
- char buf[1024];
- char* hash;
- NONFAILING(strncpy(buf, (char*)a0, sizeof(buf) - 1));
- buf[sizeof(buf) - 1] = 0;
- while ((hash = strchr(buf, '#'))) {
- *hash = '0' + (char)(a1 % 10);
- a1 /= 10;
- }
- return open(buf, a2, 0);
- }
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_open_procfs)
-static uintptr_t syz_open_procfs(uintptr_t a0, uintptr_t a1)
-{
-
- char buf[128];
- memset(buf, 0, sizeof(buf));
- if (a0 == 0) {
- NONFAILING(snprintf(buf, sizeof(buf), "/proc/self/%s", (char*)a1));
- } else if (a0 == (uintptr_t)-1) {
- NONFAILING(snprintf(buf, sizeof(buf), "/proc/thread-self/%s", (char*)a1));
- } else {
- NONFAILING(snprintf(buf, sizeof(buf), "/proc/self/task/%d/%s", (int)a0, (char*)a1));
- }
- int fd = open(buf, O_RDWR);
- if (fd == -1)
- fd = open(buf, O_RDONLY);
- return fd;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_open_pts)
-static uintptr_t syz_open_pts(uintptr_t a0, uintptr_t a1)
-{
- int ptyno = 0;
- if (ioctl(a0, TIOCGPTN, &ptyno))
- return -1;
- char buf[128];
- sprintf(buf, "/dev/pts/%d", ptyno);
- return open(buf, a1, 0);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_init_net_socket)
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE)
-const int kInitNetNsFd = 253;
-static uintptr_t syz_init_net_socket(uintptr_t domain, uintptr_t type, uintptr_t proto)
-{
- int netns = open("/proc/self/ns/net", O_RDONLY);
- if (netns == -1)
- return netns;
- if (setns(kInitNetNsFd, 0))
- return -1;
- int sock = syscall(__NR_socket, domain, type, proto);
- int err = errno;
- if (setns(netns, 0))
- fail("setns(netns) failed");
- close(netns);
- errno = err;
- return sock;
-}
-#else
-static uintptr_t syz_init_net_socket(uintptr_t domain, uintptr_t type, uintptr_t proto)
-{
- return syscall(__NR_socket, domain, type, proto);
-}
-#endif
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_genetlink_get_family_id)
-static uintptr_t syz_genetlink_get_family_id(uintptr_t name)
-{
- char buf[512] = {0};
- struct nlmsghdr* hdr = (struct nlmsghdr*)buf;
- struct genlmsghdr* genlhdr = (struct genlmsghdr*)NLMSG_DATA(hdr);
- struct nlattr* attr = (struct nlattr*)(genlhdr + 1);
- hdr->nlmsg_len = sizeof(*hdr) + sizeof(*genlhdr) + sizeof(*attr) + GENL_NAMSIZ;
- hdr->nlmsg_type = GENL_ID_CTRL;
- hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- genlhdr->cmd = CTRL_CMD_GETFAMILY;
- attr->nla_type = CTRL_ATTR_FAMILY_NAME;
- attr->nla_len = sizeof(*attr) + GENL_NAMSIZ;
- NONFAILING(strncpy((char*)(attr + 1), (char*)name, GENL_NAMSIZ));
- struct iovec iov = {hdr, hdr->nlmsg_len};
- struct sockaddr_nl addr = {0};
- addr.nl_family = AF_NETLINK;
- debug("syz_genetlink_get_family_id(%s)\n", (char*)(attr + 1));
- int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
- if (fd == -1) {
- debug("syz_genetlink_get_family_id: socket failed: %d\n", errno);
- return -1;
- }
- struct msghdr msg = {&addr, sizeof(addr), &iov, 1, NULL, 0, 0};
- if (sendmsg(fd, &msg, 0) == -1) {
- debug("syz_genetlink_get_family_id: sendmsg failed: %d\n", errno);
- close(fd);
- return -1;
- }
- ssize_t n = recv(fd, buf, sizeof(buf), 0);
- close(fd);
- if (n <= 0) {
- debug("syz_genetlink_get_family_id: recv failed: %d\n", errno);
- return -1;
- }
- if (hdr->nlmsg_type != GENL_ID_CTRL) {
- debug("syz_genetlink_get_family_id: wrong reply type: %d\n", hdr->nlmsg_type);
- return -1;
- }
- for (; (char*)attr < buf + n; attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
- if (attr->nla_type == CTRL_ATTR_FAMILY_ID)
- return *(uint16*)(attr + 1);
- }
- debug("syz_genetlink_get_family_id: no CTRL_ATTR_FAMILY_ID attr\n");
- return -1;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_mount_image) || defined(__NR_syz_read_part_table)
-extern unsigned long long procid;
-
-struct fs_image_segment {
- void* data;
- uintptr_t size;
- uintptr_t offset;
-};
-
-#define IMAGE_MAX_SEGMENTS 4096
-#define IMAGE_MAX_SIZE (129 << 20)
-
-#if defined(__i386__)
-#define SYZ_memfd_create 356
-#elif defined(__x86_64__)
-#define SYZ_memfd_create 319
-#elif defined(__arm__)
-#define SYZ_memfd_create 385
-#elif defined(__aarch64__)
-#define SYZ_memfd_create 279
-#elif defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__)
-#define SYZ_memfd_create 360
-#endif
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_read_part_table)
-static uintptr_t syz_read_part_table(uintptr_t size, uintptr_t nsegs, uintptr_t segments)
-{
- char loopname[64], linkname[64];
- int loopfd, err = 0, res = -1;
- uintptr_t i, j;
- struct fs_image_segment* segs = (struct fs_image_segment*)segments;
-
- if (nsegs > IMAGE_MAX_SEGMENTS)
- nsegs = IMAGE_MAX_SEGMENTS;
- for (i = 0; i < nsegs; i++) {
- if (segs[i].size > IMAGE_MAX_SIZE)
- segs[i].size = IMAGE_MAX_SIZE;
- segs[i].offset %= IMAGE_MAX_SIZE;
- if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
- segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
- if (size < segs[i].offset + segs[i].offset)
- size = segs[i].offset + segs[i].offset;
- }
- if (size > IMAGE_MAX_SIZE)
- size = IMAGE_MAX_SIZE;
- int memfd = syscall(SYZ_memfd_create, "syz_read_part_table", 0);
- if (memfd == -1) {
- err = errno;
- goto error;
- }
- if (ftruncate(memfd, size)) {
- err = errno;
- goto error_close_memfd;
- }
- for (i = 0; i < nsegs; i++) {
- if (pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset) < 0) {
- debug("syz_read_part_table: pwrite[%u] failed: %d\n", (int)i, errno);
- }
- }
- snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
- loopfd = open(loopname, O_RDWR);
- if (loopfd == -1) {
- err = errno;
- goto error_close_memfd;
- }
- if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
- if (errno != EBUSY) {
- err = errno;
- goto error_close_loop;
- }
- ioctl(loopfd, LOOP_CLR_FD, 0);
- usleep(1000);
- if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
- err = errno;
- goto error_close_loop;
- }
- }
- struct loop_info64 info;
- if (ioctl(loopfd, LOOP_GET_STATUS64, &info)) {
- err = errno;
- goto error_clear_loop;
- }
-#if defined(SYZ_EXECUTOR)
- cover_reset(0);
-#endif
- info.lo_flags |= LO_FLAGS_PARTSCAN;
- if (ioctl(loopfd, LOOP_SET_STATUS64, &info)) {
- err = errno;
- goto error_clear_loop;
- }
- res = 0;
- for (i = 1, j = 0; i < 8; i++) {
- snprintf(loopname, sizeof(loopname), "/dev/loop%llup%d", procid, (int)i);
- struct stat statbuf;
- if (stat(loopname, &statbuf) == 0) {
- snprintf(linkname, sizeof(linkname), "./file%d", (int)j++);
- if (symlink(loopname, linkname)) {
- debug("syz_read_part_table: symlink(%s, %s) failed: %d\n", loopname, linkname, errno);
- }
- }
- }
-error_clear_loop:
- ioctl(loopfd, LOOP_CLR_FD, 0);
-error_close_loop:
- close(loopfd);
-error_close_memfd:
- close(memfd);
-error:
- errno = err;
- return res;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_mount_image)
-static uintptr_t syz_mount_image(uintptr_t fsarg, uintptr_t dir, uintptr_t size, uintptr_t nsegs, uintptr_t segments, uintptr_t flags, uintptr_t optsarg)
-{
- char loopname[64], fs[32], opts[256];
- int loopfd, err = 0, res = -1;
- uintptr_t i;
- struct fs_image_segment* segs = (struct fs_image_segment*)segments;
-
- if (nsegs > IMAGE_MAX_SEGMENTS)
- nsegs = IMAGE_MAX_SEGMENTS;
- for (i = 0; i < nsegs; i++) {
- if (segs[i].size > IMAGE_MAX_SIZE)
- segs[i].size = IMAGE_MAX_SIZE;
- segs[i].offset %= IMAGE_MAX_SIZE;
- if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
- segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
- if (size < segs[i].offset + segs[i].offset)
- size = segs[i].offset + segs[i].offset;
- }
- if (size > IMAGE_MAX_SIZE)
- size = IMAGE_MAX_SIZE;
- int memfd = syscall(SYZ_memfd_create, "syz_mount_image", 0);
- if (memfd == -1) {
- err = errno;
- goto error;
- }
- if (ftruncate(memfd, size)) {
- err = errno;
- goto error_close_memfd;
- }
- for (i = 0; i < nsegs; i++) {
- if (pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset) < 0) {
- debug("syz_mount_image: pwrite[%u] failed: %d\n", (int)i, errno);
- }
- }
- snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
- loopfd = open(loopname, O_RDWR);
- if (loopfd == -1) {
- err = errno;
- goto error_close_memfd;
- }
- if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
- if (errno != EBUSY) {
- err = errno;
- goto error_close_loop;
- }
- ioctl(loopfd, LOOP_CLR_FD, 0);
- usleep(1000);
- if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
- err = errno;
- goto error_close_loop;
- }
- }
- mkdir((char*)dir, 0777);
- memset(fs, 0, sizeof(fs));
- NONFAILING(strncpy(fs, (char*)fsarg, sizeof(fs) - 1));
- memset(opts, 0, sizeof(opts));
- NONFAILING(strncpy(opts, (char*)optsarg, sizeof(opts) - 32));
- if (strcmp(fs, "iso9660") == 0) {
- flags |= MS_RDONLY;
- } else if (strncmp(fs, "ext", 3) == 0) {
- if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
- strcat(opts, ",errors=continue");
- } else if (strcmp(fs, "xfs") == 0) {
- strcat(opts, ",nouuid");
- }
- debug("syz_mount_image: size=%llu segs=%llu loop='%s' dir='%s' fs='%s' flags=%llu opts='%s'\n", (uint64)size, (uint64)nsegs, loopname, (char*)dir, fs, (uint64)flags, opts);
-#if defined(SYZ_EXECUTOR)
- cover_reset(0);
-#endif
- if (mount(loopname, (char*)dir, fs, flags, opts)) {
- err = errno;
- goto error_clear_loop;
- }
- res = 0;
-error_clear_loop:
- ioctl(loopfd, LOOP_CLR_FD, 0);
-error_close_loop:
- close(loopfd);
-error_close_memfd:
- close(memfd);
-error:
- errno = err;
- return res;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_kvm_setup_cpu)
-#if defined(__x86_64__)
-
-
-
-const char kvm_asm16_cpl3[] = "\x0f\x20\xc0\x66\x83\xc8\x01\x0f\x22\xc0\xb8\xa0\x00\x0f\x00\xd8\xb8\x2b\x00\x8e\xd8\x8e\xc0\x8e\xe0\x8e\xe8\xbc\x00\x01\xc7\x06\x00\x01\x1d\xba\xc7\x06\x02\x01\x23\x00\xc7\x06\x04\x01\x00\x01\xc7\x06\x06\x01\x2b\x00\xcb";
-const char kvm_asm32_paged[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0";
-const char kvm_asm32_vm86[] = "\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00";
-const char kvm_asm32_paged_vm86[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00";
-const char kvm_asm64_vm86[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\x66\xb8\xb8\x00\x0f\x00\xd8\xea\x00\x00\x00\x00\xd0\x00";
-const char kvm_asm64_enable_long[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8";
-const char kvm_asm64_init_vm[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc1\x3a\x00\x00\x00\x0f\x32\x48\x83\xc8\x05\x0f\x30\x0f\x20\xe0\x48\x0d\x00\x20\x00\x00\x0f\x22\xe0\x48\xc7\xc1\x80\x04\x00\x00\x0f\x32\x48\xc7\xc2\x00\x60\x00\x00\x89\x02\x48\xc7\xc2\x00\x70\x00\x00\x89\x02\x48\xc7\xc0\x00\x5f\x00\x00\xf3\x0f\xc7\x30\x48\xc7\xc0\x08\x5f\x00\x00\x66\x0f\xc7\x30\x0f\xc7\x30\x48\xc7\xc1\x81\x04\x00\x00\x0f\x32\x48\x83\xc8\x3f\x48\x21\xd0\x48\xc7\xc2\x00\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x40\x00\x00\x48\xb8\x84\x9e\x99\xf3\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x40\x00\x00\x48\xc7\xc0\x81\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x83\x04\x00\x00\x0f\x32\x48\x0d\xff\x6f\x03\x00\x48\x21\xd0\x48\xc7\xc2\x0c\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x84\x04\x00\x00\x0f\x32\x48\x0d\xff\x17\x00\x00\x48\x21\xd0\x48\xc7\xc2\x12\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x2c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x28\x00\x00\x48\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x0c\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc0\x58\x00\x00\x00\x48\xc7\xc2\x00\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc0\xd8\x00\x00\x00\x48\xc7\xc2\x0c\x0c\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x2c\x00\x00\x48\xc7\xc0\x00\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x4c\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xd8\x48\xc7\xc2\x02\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xe0\x48\xc7\xc2\x04\x6c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc2\x06\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x6c\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x6c\x00\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x6c\x00\x00\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x6c\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x6c\x00\x00\x48\x8b\x04\x25\x10\x5f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x00\x00\x00\x48\xc7\xc0\x01\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x00\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc1\x77\x02\x00\x00\x0f\x32\x48\xc1\xe2\x20\x48\x09\xd0\x48\xc7\xc2\x00\x2c\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc2\x04\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x40\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x60\x00\x00\x48\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x02\x60\x00\x00\x48\xc7\xc0\xff\xff\xff\xff\x0f\x79\xd0\x48\xc7\xc2\x1c\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x20\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x08\x00\x00\x48\xc7\xc0\x50\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x08\x00\x00\x48\xc7\xc0\x58\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x08\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x08\x00\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x68\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x68\x00\x00\x48\xc7\xc0\x00\x3a\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x68\x00\x00\x48\xc7\xc0\x00\x10\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x18\x68\x00\x00\x48\xc7\xc0\x00\x38\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x00\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x02\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x04\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x08\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x48\x00\x00\x48\xc7\xc0\xff\xff\x0f\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x48\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x12\x48\x00\x00\x48\xc7\xc0\xff\x1f\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x14\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x16\x48\x00\x00\x48\xc7\xc0\x9b\x20\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x18\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1a\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x48\x00\x00\x48\xc7\xc0\x93\x40\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x48\x00\x00\x48\xc7\xc0\x82\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x22\x48\x00\x00\x48\xc7\xc0\x8b\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1c\x68\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x1e\x68\x00\x00\x48\xc7\xc0\x00\x91\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x20\x68\x00\x00\x48\xc7\xc0\x02\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x06\x28\x00\x00\x48\xc7\xc0\x00\x05\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0a\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0c\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x0e\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x48\xc7\xc2\x10\x28\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x79\xd0\x0f\x20\xc0\x48\xc7\xc2\x00\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xd8\x48\xc7\xc2\x02\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x0f\x20\xe0\x48\xc7\xc2\x04\x68\x00\x00\x48\x89\xc0\x0f\x79\xd0\x48\xc7\xc0\x18\x5f\x00\x00\x48\x8b\x10\x48\xc7\xc0\x20\x5f\x00\x00\x48\x8b\x08\x48\x31\xc0\x0f\x78\xd0\x48\x31\xc8\x0f\x79\xd0\x0f\x01\xc2\x48\xc7\xc2\x00\x44\x00\x00\x0f\x78\xd0\xf4";
-const char kvm_asm64_vm_exit[] = "\x48\xc7\xc3\x00\x44\x00\x00\x0f\x78\xda\x48\xc7\xc3\x02\x44\x00\x00\x0f\x78\xd9\x48\xc7\xc0\x00\x64\x00\x00\x0f\x78\xc0\x48\xc7\xc3\x1e\x68\x00\x00\x0f\x78\xdb\xf4";
-const char kvm_asm64_cpl3[] = "\x0f\x20\xc0\x0d\x00\x00\x00\x80\x0f\x22\xc0\xea\xde\xc0\xad\x0b\x50\x00\x48\xc7\xc0\xd8\x00\x00\x00\x0f\x00\xd8\x48\xc7\xc0\x6b\x00\x00\x00\x8e\xd8\x8e\xc0\x8e\xe0\x8e\xe8\x48\xc7\xc4\x80\x0f\x00\x00\x48\xc7\x04\x24\x1d\xba\x00\x00\x48\xc7\x44\x24\x04\x63\x00\x00\x00\x48\xc7\x44\x24\x08\x80\x0f\x00\x00\x48\xc7\x44\x24\x0c\x6b\x00\x00\x00\xcb";
-
-#define ADDR_TEXT 0x0000
-#define ADDR_GDT 0x1000
-#define ADDR_LDT 0x1800
-#define ADDR_PML4 0x2000
-#define ADDR_PDP 0x3000
-#define ADDR_PD 0x4000
-#define ADDR_STACK0 0x0f80
-#define ADDR_VAR_HLT 0x2800
-#define ADDR_VAR_SYSRET 0x2808
-#define ADDR_VAR_SYSEXIT 0x2810
-#define ADDR_VAR_IDT 0x3800
-#define ADDR_VAR_TSS64 0x3a00
-#define ADDR_VAR_TSS64_CPL3 0x3c00
-#define ADDR_VAR_TSS16 0x3d00
-#define ADDR_VAR_TSS16_2 0x3e00
-#define ADDR_VAR_TSS16_CPL3 0x3f00
-#define ADDR_VAR_TSS32 0x4800
-#define ADDR_VAR_TSS32_2 0x4a00
-#define ADDR_VAR_TSS32_CPL3 0x4c00
-#define ADDR_VAR_TSS32_VM86 0x4e00
-#define ADDR_VAR_VMXON_PTR 0x5f00
-#define ADDR_VAR_VMCS_PTR 0x5f08
-#define ADDR_VAR_VMEXIT_PTR 0x5f10
-#define ADDR_VAR_VMWRITE_FLD 0x5f18
-#define ADDR_VAR_VMWRITE_VAL 0x5f20
-#define ADDR_VAR_VMXON 0x6000
-#define ADDR_VAR_VMCS 0x7000
-#define ADDR_VAR_VMEXIT_CODE 0x9000
-#define ADDR_VAR_USER_CODE 0x9100
-#define ADDR_VAR_USER_CODE2 0x9120
-
-#define SEL_LDT (1 << 3)
-#define SEL_CS16 (2 << 3)
-#define SEL_DS16 (3 << 3)
-#define SEL_CS16_CPL3 ((4 << 3) + 3)
-#define SEL_DS16_CPL3 ((5 << 3) + 3)
-#define SEL_CS32 (6 << 3)
-#define SEL_DS32 (7 << 3)
-#define SEL_CS32_CPL3 ((8 << 3) + 3)
-#define SEL_DS32_CPL3 ((9 << 3) + 3)
-#define SEL_CS64 (10 << 3)
-#define SEL_DS64 (11 << 3)
-#define SEL_CS64_CPL3 ((12 << 3) + 3)
-#define SEL_DS64_CPL3 ((13 << 3) + 3)
-#define SEL_CGATE16 (14 << 3)
-#define SEL_TGATE16 (15 << 3)
-#define SEL_CGATE32 (16 << 3)
-#define SEL_TGATE32 (17 << 3)
-#define SEL_CGATE64 (18 << 3)
-#define SEL_CGATE64_HI (19 << 3)
-#define SEL_TSS16 (20 << 3)
-#define SEL_TSS16_2 (21 << 3)
-#define SEL_TSS16_CPL3 ((22 << 3) + 3)
-#define SEL_TSS32 (23 << 3)
-#define SEL_TSS32_2 (24 << 3)
-#define SEL_TSS32_CPL3 ((25 << 3) + 3)
-#define SEL_TSS32_VM86 (26 << 3)
-#define SEL_TSS64 (27 << 3)
-#define SEL_TSS64_HI (28 << 3)
-#define SEL_TSS64_CPL3 ((29 << 3) + 3)
-#define SEL_TSS64_CPL3_HI (30 << 3)
-
-#define MSR_IA32_FEATURE_CONTROL 0x3a
-#define MSR_IA32_VMX_BASIC 0x480
-#define MSR_IA32_SMBASE 0x9e
-#define MSR_IA32_SYSENTER_CS 0x174
-#define MSR_IA32_SYSENTER_ESP 0x175
-#define MSR_IA32_SYSENTER_EIP 0x176
-#define MSR_IA32_STAR 0xC0000081
-#define MSR_IA32_LSTAR 0xC0000082
-#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48B
-
-#define NEXT_INSN $0xbadc0de
-#define PREFIX_SIZE 0xba1d
-
-#ifndef KVM_SMI
-#define KVM_SMI _IO(KVMIO, 0xb7)
-#endif
-
-#define CR0_PE 1
-#define CR0_MP (1 << 1)
-#define CR0_EM (1 << 2)
-#define CR0_TS (1 << 3)
-#define CR0_ET (1 << 4)
-#define CR0_NE (1 << 5)
-#define CR0_WP (1 << 16)
-#define CR0_AM (1 << 18)
-#define CR0_NW (1 << 29)
-#define CR0_CD (1 << 30)
-#define CR0_PG (1 << 31)
-
-#define CR4_VME 1
-#define CR4_PVI (1 << 1)
-#define CR4_TSD (1 << 2)
-#define CR4_DE (1 << 3)
-#define CR4_PSE (1 << 4)
-#define CR4_PAE (1 << 5)
-#define CR4_MCE (1 << 6)
-#define CR4_PGE (1 << 7)
-#define CR4_PCE (1 << 8)
-#define CR4_OSFXSR (1 << 8)
-#define CR4_OSXMMEXCPT (1 << 10)
-#define CR4_UMIP (1 << 11)
-#define CR4_VMXE (1 << 13)
-#define CR4_SMXE (1 << 14)
-#define CR4_FSGSBASE (1 << 16)
-#define CR4_PCIDE (1 << 17)
-#define CR4_OSXSAVE (1 << 18)
-#define CR4_SMEP (1 << 20)
-#define CR4_SMAP (1 << 21)
-#define CR4_PKE (1 << 22)
-
-#define EFER_SCE 1
-#define EFER_LME (1 << 8)
-#define EFER_LMA (1 << 10)
-#define EFER_NXE (1 << 11)
-#define EFER_SVME (1 << 12)
-#define EFER_LMSLE (1 << 13)
-#define EFER_FFXSR (1 << 14)
-#define EFER_TCE (1 << 15)
-
-#define PDE32_PRESENT 1
-#define PDE32_RW (1 << 1)
-#define PDE32_USER (1 << 2)
-#define PDE32_PS (1 << 7)
-
-#define PDE64_PRESENT 1
-#define PDE64_RW (1 << 1)
-#define PDE64_USER (1 << 2)
-#define PDE64_ACCESSED (1 << 5)
-#define PDE64_DIRTY (1 << 6)
-#define PDE64_PS (1 << 7)
-#define PDE64_G (1 << 8)
-
-struct tss16 {
- uint16 prev;
- uint16 sp0;
- uint16 ss0;
- uint16 sp1;
- uint16 ss1;
- uint16 sp2;
- uint16 ss2;
- uint16 ip;
- uint16 flags;
- uint16 ax;
- uint16 cx;
- uint16 dx;
- uint16 bx;
- uint16 sp;
- uint16 bp;
- uint16 si;
- uint16 di;
- uint16 es;
- uint16 cs;
- uint16 ss;
- uint16 ds;
- uint16 ldt;
-} __attribute__((packed));
-
-struct tss32 {
- uint16 prev, prevh;
- uint32 sp0;
- uint16 ss0, ss0h;
- uint32 sp1;
- uint16 ss1, ss1h;
- uint32 sp2;
- uint16 ss2, ss2h;
- uint32 cr3;
- uint32 ip;
- uint32 flags;
- uint32 ax;
- uint32 cx;
- uint32 dx;
- uint32 bx;
- uint32 sp;
- uint32 bp;
- uint32 si;
- uint32 di;
- uint16 es, esh;
- uint16 cs, csh;
- uint16 ss, ssh;
- uint16 ds, dsh;
- uint16 fs, fsh;
- uint16 gs, gsh;
- uint16 ldt, ldth;
- uint16 trace;
- uint16 io_bitmap;
-} __attribute__((packed));
-
-struct tss64 {
- uint32 reserved0;
- uint64 rsp[3];
- uint64 reserved1;
- uint64 ist[7];
- uint64 reserved2;
- uint32 reserved3;
- uint32 io_bitmap;
-} __attribute__((packed));
-
-static void fill_segment_descriptor(uint64* dt, uint64* lt, struct kvm_segment* seg)
-{
- uint16 index = seg->selector >> 3;
- uint64 limit = seg->g ? seg->limit >> 12 : seg->limit;
- uint64 sd = (limit & 0xffff) | (seg->base & 0xffffff) << 16 | (uint64)seg->type << 40 | (uint64)seg->s << 44 | (uint64)seg->dpl << 45 | (uint64)seg->present << 47 | (limit & 0xf0000ULL) << 48 | (uint64)seg->avl << 52 | (uint64)seg->l << 53 | (uint64)seg->db << 54 | (uint64)seg->g << 55 | (seg->base & 0xff000000ULL) << 56;
- NONFAILING(dt[index] = sd);
- NONFAILING(lt[index] = sd);
-}
-
-static void fill_segment_descriptor_dword(uint64* dt, uint64* lt, struct kvm_segment* seg)
-{
- fill_segment_descriptor(dt, lt, seg);
- uint16 index = seg->selector >> 3;
- NONFAILING(dt[index + 1] = 0);
- NONFAILING(lt[index + 1] = 0);
-}
-
-static void setup_syscall_msrs(int cpufd, uint16 sel_cs, uint16 sel_cs_cpl3)
-{
- char buf[sizeof(struct kvm_msrs) + 5 * sizeof(struct kvm_msr_entry)];
- memset(buf, 0, sizeof(buf));
- struct kvm_msrs* msrs = (struct kvm_msrs*)buf;
- struct kvm_msr_entry* entries = msrs->entries;
- msrs->nmsrs = 5;
- entries[0].index = MSR_IA32_SYSENTER_CS;
- entries[0].data = sel_cs;
- entries[1].index = MSR_IA32_SYSENTER_ESP;
- entries[1].data = ADDR_STACK0;
- entries[2].index = MSR_IA32_SYSENTER_EIP;
- entries[2].data = ADDR_VAR_SYSEXIT;
- entries[3].index = MSR_IA32_STAR;
- entries[3].data = ((uint64)sel_cs << 32) | ((uint64)sel_cs_cpl3 << 48);
- entries[4].index = MSR_IA32_LSTAR;
- entries[4].data = ADDR_VAR_SYSRET;
- ioctl(cpufd, KVM_SET_MSRS, msrs);
-}
-
-static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t guest_mem)
-{
- sregs->idt.base = guest_mem + ADDR_VAR_IDT;
- sregs->idt.limit = 0x1ff;
- uint64* idt = (uint64*)(host_mem + sregs->idt.base);
- int i;
- for (i = 0; i < 32; i++) {
- struct kvm_segment gate;
- gate.selector = i << 3;
- switch (i % 6) {
- case 0:
- gate.type = 6;
- gate.base = SEL_CS16;
- break;
- case 1:
- gate.type = 7;
- gate.base = SEL_CS16;
- break;
- case 2:
- gate.type = 3;
- gate.base = SEL_TGATE16;
- break;
- case 3:
- gate.type = 14;
- gate.base = SEL_CS32;
- break;
- case 4:
- gate.type = 15;
- gate.base = SEL_CS32;
- break;
- case 6:
- gate.type = 11;
- gate.base = SEL_TGATE32;
- break;
- }
- gate.limit = guest_mem + ADDR_VAR_USER_CODE2;
- gate.present = 1;
- gate.dpl = 0;
- gate.s = 0;
- gate.g = 0;
- gate.db = 0;
- gate.l = 0;
- gate.avl = 0;
- fill_segment_descriptor(idt, idt, &gate);
- }
-}
-
-static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t guest_mem)
-{
- sregs->idt.base = guest_mem + ADDR_VAR_IDT;
- sregs->idt.limit = 0x1ff;
- uint64* idt = (uint64*)(host_mem + sregs->idt.base);
- int i;
- for (i = 0; i < 32; i++) {
- struct kvm_segment gate;
- gate.selector = (i * 2) << 3;
- gate.type = (i & 1) ? 14 : 15;
- gate.base = SEL_CS64;
- gate.limit = guest_mem + ADDR_VAR_USER_CODE2;
- gate.present = 1;
- gate.dpl = 0;
- gate.s = 0;
- gate.g = 0;
- gate.db = 0;
- gate.l = 0;
- gate.avl = 0;
- fill_segment_descriptor_dword(idt, idt, &gate);
- }
-}
-
-struct kvm_text {
- uintptr_t typ;
- const void* text;
- uintptr_t size;
-};
-
-struct kvm_opt {
- uint64 typ;
- uint64 val;
-};
-
-#define KVM_SETUP_PAGING (1 << 0)
-#define KVM_SETUP_PAE (1 << 1)
-#define KVM_SETUP_PROTECTED (1 << 2)
-#define KVM_SETUP_CPL3 (1 << 3)
-#define KVM_SETUP_VIRT86 (1 << 4)
-#define KVM_SETUP_SMM (1 << 5)
-#define KVM_SETUP_VM (1 << 6)
-
-static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7)
-{
- const int vmfd = a0;
- const int cpufd = a1;
- char* const host_mem = (char*)a2;
- const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3;
- const uintptr_t text_count = a4;
- const uintptr_t flags = a5;
- const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6;
- uintptr_t opt_count = a7;
-
- const uintptr_t page_size = 4 << 10;
- const uintptr_t ioapic_page = 10;
- const uintptr_t guest_mem_size = 24 * page_size;
- const uintptr_t guest_mem = 0;
-
- (void)text_count;
- int text_type = 0;
- const void* text = 0;
- uintptr_t text_size = 0;
- NONFAILING(text_type = text_array_ptr[0].typ);
- NONFAILING(text = text_array_ptr[0].text);
- NONFAILING(text_size = text_array_ptr[0].size);
-
- uintptr_t i;
- for (i = 0; i < guest_mem_size / page_size; i++) {
- struct kvm_userspace_memory_region memreg;
- memreg.slot = i;
- memreg.flags = 0;
- memreg.guest_phys_addr = guest_mem + i * page_size;
- if (i == ioapic_page)
- memreg.guest_phys_addr = 0xfec00000;
- memreg.memory_size = page_size;
- memreg.userspace_addr = (uintptr_t)host_mem + i * page_size;
- ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
- }
- struct kvm_userspace_memory_region memreg;
- memreg.slot = 1 + (1 << 16);
- memreg.flags = 0;
- memreg.guest_phys_addr = 0x30000;
- memreg.memory_size = 64 << 10;
- memreg.userspace_addr = (uintptr_t)host_mem;
- ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
-
- struct kvm_sregs sregs;
- if (ioctl(cpufd, KVM_GET_SREGS, &sregs))
- return -1;
-
- struct kvm_regs regs;
- memset(&regs, 0, sizeof(regs));
- regs.rip = guest_mem + ADDR_TEXT;
- regs.rsp = ADDR_STACK0;
-
- sregs.gdt.base = guest_mem + ADDR_GDT;
- sregs.gdt.limit = 256 * sizeof(uint64) - 1;
- uint64* gdt = (uint64*)(host_mem + sregs.gdt.base);
-
- struct kvm_segment seg_ldt;
- seg_ldt.selector = SEL_LDT;
- seg_ldt.type = 2;
- seg_ldt.base = guest_mem + ADDR_LDT;
- seg_ldt.limit = 256 * sizeof(uint64) - 1;
- seg_ldt.present = 1;
- seg_ldt.dpl = 0;
- seg_ldt.s = 0;
- seg_ldt.g = 0;
- seg_ldt.db = 1;
- seg_ldt.l = 0;
- sregs.ldt = seg_ldt;
- uint64* ldt = (uint64*)(host_mem + sregs.ldt.base);
-
- struct kvm_segment seg_cs16;
- seg_cs16.selector = SEL_CS16;
- seg_cs16.type = 11;
- seg_cs16.base = 0;
- seg_cs16.limit = 0xfffff;
- seg_cs16.present = 1;
- seg_cs16.dpl = 0;
- seg_cs16.s = 1;
- seg_cs16.g = 0;
- seg_cs16.db = 0;
- seg_cs16.l = 0;
-
- struct kvm_segment seg_ds16 = seg_cs16;
- seg_ds16.selector = SEL_DS16;
- seg_ds16.type = 3;
-
- struct kvm_segment seg_cs16_cpl3 = seg_cs16;
- seg_cs16_cpl3.selector = SEL_CS16_CPL3;
- seg_cs16_cpl3.dpl = 3;
-
- struct kvm_segment seg_ds16_cpl3 = seg_ds16;
- seg_ds16_cpl3.selector = SEL_DS16_CPL3;
- seg_ds16_cpl3.dpl = 3;
-
- struct kvm_segment seg_cs32 = seg_cs16;
- seg_cs32.selector = SEL_CS32;
- seg_cs32.db = 1;
-
- struct kvm_segment seg_ds32 = seg_ds16;
- seg_ds32.selector = SEL_DS32;
- seg_ds32.db = 1;
-
- struct kvm_segment seg_cs32_cpl3 = seg_cs32;
- seg_cs32_cpl3.selector = SEL_CS32_CPL3;
- seg_cs32_cpl3.dpl = 3;
-
- struct kvm_segment seg_ds32_cpl3 = seg_ds32;
- seg_ds32_cpl3.selector = SEL_DS32_CPL3;
- seg_ds32_cpl3.dpl = 3;
-
- struct kvm_segment seg_cs64 = seg_cs16;
- seg_cs64.selector = SEL_CS64;
- seg_cs64.l = 1;
-
- struct kvm_segment seg_ds64 = seg_ds32;
- seg_ds64.selector = SEL_DS64;
-
- struct kvm_segment seg_cs64_cpl3 = seg_cs64;
- seg_cs64_cpl3.selector = SEL_CS64_CPL3;
- seg_cs64_cpl3.dpl = 3;
-
- struct kvm_segment seg_ds64_cpl3 = seg_ds64;
- seg_ds64_cpl3.selector = SEL_DS64_CPL3;
- seg_ds64_cpl3.dpl = 3;
-
- struct kvm_segment seg_tss32;
- seg_tss32.selector = SEL_TSS32;
- seg_tss32.type = 9;
- seg_tss32.base = ADDR_VAR_TSS32;
- seg_tss32.limit = 0x1ff;
- seg_tss32.present = 1;
- seg_tss32.dpl = 0;
- seg_tss32.s = 0;
- seg_tss32.g = 0;
- seg_tss32.db = 0;
- seg_tss32.l = 0;
-
- struct kvm_segment seg_tss32_2 = seg_tss32;
- seg_tss32_2.selector = SEL_TSS32_2;
- seg_tss32_2.base = ADDR_VAR_TSS32_2;
-
- struct kvm_segment seg_tss32_cpl3 = seg_tss32;
- seg_tss32_cpl3.selector = SEL_TSS32_CPL3;
- seg_tss32_cpl3.base = ADDR_VAR_TSS32_CPL3;
-
- struct kvm_segment seg_tss32_vm86 = seg_tss32;
- seg_tss32_vm86.selector = SEL_TSS32_VM86;
- seg_tss32_vm86.base = ADDR_VAR_TSS32_VM86;
-
- struct kvm_segment seg_tss16 = seg_tss32;
- seg_tss16.selector = SEL_TSS16;
- seg_tss16.base = ADDR_VAR_TSS16;
- seg_tss16.limit = 0xff;
- seg_tss16.type = 1;
-
- struct kvm_segment seg_tss16_2 = seg_tss16;
- seg_tss16_2.selector = SEL_TSS16_2;
- seg_tss16_2.base = ADDR_VAR_TSS16_2;
- seg_tss16_2.dpl = 0;
-
- struct kvm_segment seg_tss16_cpl3 = seg_tss16;
- seg_tss16_cpl3.selector = SEL_TSS16_CPL3;
- seg_tss16_cpl3.base = ADDR_VAR_TSS16_CPL3;
- seg_tss16_cpl3.dpl = 3;
-
- struct kvm_segment seg_tss64 = seg_tss32;
- seg_tss64.selector = SEL_TSS64;
- seg_tss64.base = ADDR_VAR_TSS64;
- seg_tss64.limit = 0x1ff;
-
- struct kvm_segment seg_tss64_cpl3 = seg_tss64;
- seg_tss64_cpl3.selector = SEL_TSS64_CPL3;
- seg_tss64_cpl3.base = ADDR_VAR_TSS64_CPL3;
- seg_tss64_cpl3.dpl = 3;
-
- struct kvm_segment seg_cgate16;
- seg_cgate16.selector = SEL_CGATE16;
- seg_cgate16.type = 4;
- seg_cgate16.base = SEL_CS16 | (2 << 16);
- seg_cgate16.limit = ADDR_VAR_USER_CODE2;
- seg_cgate16.present = 1;
- seg_cgate16.dpl = 0;
- seg_cgate16.s = 0;
- seg_cgate16.g = 0;
- seg_cgate16.db = 0;
- seg_cgate16.l = 0;
- seg_cgate16.avl = 0;
-
- struct kvm_segment seg_tgate16 = seg_cgate16;
- seg_tgate16.selector = SEL_TGATE16;
- seg_tgate16.type = 3;
- seg_cgate16.base = SEL_TSS16_2;
- seg_tgate16.limit = 0;
-
- struct kvm_segment seg_cgate32 = seg_cgate16;
- seg_cgate32.selector = SEL_CGATE32;
- seg_cgate32.type = 12;
- seg_cgate32.base = SEL_CS32 | (2 << 16);
-
- struct kvm_segment seg_tgate32 = seg_cgate32;
- seg_tgate32.selector = SEL_TGATE32;
- seg_tgate32.type = 11;
- seg_tgate32.base = SEL_TSS32_2;
- seg_tgate32.limit = 0;
-
- struct kvm_segment seg_cgate64 = seg_cgate16;
- seg_cgate64.selector = SEL_CGATE64;
- seg_cgate64.type = 12;
- seg_cgate64.base = SEL_CS64;
-
- int kvmfd = open("/dev/kvm", O_RDWR);
- char buf[sizeof(struct kvm_cpuid2) + 128 * sizeof(struct kvm_cpuid_entry2)];
- memset(buf, 0, sizeof(buf));
- struct kvm_cpuid2* cpuid = (struct kvm_cpuid2*)buf;
- cpuid->nent = 128;
- ioctl(kvmfd, KVM_GET_SUPPORTED_CPUID, cpuid);
- ioctl(cpufd, KVM_SET_CPUID2, cpuid);
- close(kvmfd);
-
- const char* text_prefix = 0;
- int text_prefix_size = 0;
- char* host_text = host_mem + ADDR_TEXT;
-
- if (text_type == 8) {
- if (flags & KVM_SETUP_SMM) {
- if (flags & KVM_SETUP_PROTECTED) {
- sregs.cs = seg_cs16;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
- sregs.cr0 |= CR0_PE;
- } else {
- sregs.cs.selector = 0;
- sregs.cs.base = 0;
- }
-
- NONFAILING(*(host_mem + ADDR_TEXT) = 0xf4);
- host_text = host_mem + 0x8000;
-
- ioctl(cpufd, KVM_SMI, 0);
- } else if (flags & KVM_SETUP_VIRT86) {
- sregs.cs = seg_cs32;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
- sregs.cr0 |= CR0_PE;
- sregs.efer |= EFER_SCE;
-
- setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3);
- setup_32bit_idt(&sregs, host_mem, guest_mem);
-
- if (flags & KVM_SETUP_PAGING) {
- uint64 pd_addr = guest_mem + ADDR_PD;
- uint64* pd = (uint64*)(host_mem + ADDR_PD);
- NONFAILING(pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS);
- sregs.cr3 = pd_addr;
- sregs.cr4 |= CR4_PSE;
-
- text_prefix = kvm_asm32_paged_vm86;
- text_prefix_size = sizeof(kvm_asm32_paged_vm86) - 1;
- } else {
- text_prefix = kvm_asm32_vm86;
- text_prefix_size = sizeof(kvm_asm32_vm86) - 1;
- }
- } else {
- sregs.cs.selector = 0;
- sregs.cs.base = 0;
- }
- } else if (text_type == 16) {
- if (flags & KVM_SETUP_CPL3) {
- sregs.cs = seg_cs16;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
-
- text_prefix = kvm_asm16_cpl3;
- text_prefix_size = sizeof(kvm_asm16_cpl3) - 1;
- } else {
- sregs.cr0 |= CR0_PE;
- sregs.cs = seg_cs16;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16;
- }
- } else if (text_type == 32) {
- sregs.cr0 |= CR0_PE;
- sregs.efer |= EFER_SCE;
-
- setup_syscall_msrs(cpufd, SEL_CS32, SEL_CS32_CPL3);
- setup_32bit_idt(&sregs, host_mem, guest_mem);
-
- if (flags & KVM_SETUP_SMM) {
- sregs.cs = seg_cs32;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
-
- NONFAILING(*(host_mem + ADDR_TEXT) = 0xf4);
- host_text = host_mem + 0x8000;
-
- ioctl(cpufd, KVM_SMI, 0);
- } else if (flags & KVM_SETUP_PAGING) {
- sregs.cs = seg_cs32;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
-
- uint64 pd_addr = guest_mem + ADDR_PD;
- uint64* pd = (uint64*)(host_mem + ADDR_PD);
- NONFAILING(pd[0] = PDE32_PRESENT | PDE32_RW | PDE32_USER | PDE32_PS);
- sregs.cr3 = pd_addr;
- sregs.cr4 |= CR4_PSE;
-
- text_prefix = kvm_asm32_paged;
- text_prefix_size = sizeof(kvm_asm32_paged) - 1;
- } else if (flags & KVM_SETUP_CPL3) {
- sregs.cs = seg_cs32_cpl3;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32_cpl3;
- } else {
- sregs.cs = seg_cs32;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
- }
- } else {
- sregs.efer |= EFER_LME | EFER_SCE;
- sregs.cr0 |= CR0_PE;
-
- setup_syscall_msrs(cpufd, SEL_CS64, SEL_CS64_CPL3);
- setup_64bit_idt(&sregs, host_mem, guest_mem);
-
- sregs.cs = seg_cs32;
- sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds32;
-
- uint64 pml4_addr = guest_mem + ADDR_PML4;
- uint64* pml4 = (uint64*)(host_mem + ADDR_PML4);
- uint64 pdpt_addr = guest_mem + ADDR_PDP;
- uint64* pdpt = (uint64*)(host_mem + ADDR_PDP);
- uint64 pd_addr = guest_mem + ADDR_PD;
- uint64* pd = (uint64*)(host_mem + ADDR_PD);
- NONFAILING(pml4[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pdpt_addr);
- NONFAILING(pdpt[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | pd_addr);
- NONFAILING(pd[0] = PDE64_PRESENT | PDE64_RW | PDE64_USER | PDE64_PS);
- sregs.cr3 = pml4_addr;
- sregs.cr4 |= CR4_PAE;
-
- if (flags & KVM_SETUP_VM) {
- sregs.cr0 |= CR0_NE;
-
- NONFAILING(*((uint64*)(host_mem + ADDR_VAR_VMXON_PTR)) = ADDR_VAR_VMXON);
- NONFAILING(*((uint64*)(host_mem + ADDR_VAR_VMCS_PTR)) = ADDR_VAR_VMCS);
- NONFAILING(memcpy(host_mem + ADDR_VAR_VMEXIT_CODE, kvm_asm64_vm_exit, sizeof(kvm_asm64_vm_exit) - 1));
- NONFAILING(*((uint64*)(host_mem + ADDR_VAR_VMEXIT_PTR)) = ADDR_VAR_VMEXIT_CODE);
-
- text_prefix = kvm_asm64_init_vm;
- text_prefix_size = sizeof(kvm_asm64_init_vm) - 1;
- } else if (flags & KVM_SETUP_CPL3) {
- text_prefix = kvm_asm64_cpl3;
- text_prefix_size = sizeof(kvm_asm64_cpl3) - 1;
- } else {
- text_prefix = kvm_asm64_enable_long;
- text_prefix_size = sizeof(kvm_asm64_enable_long) - 1;
- }
- }
-
- struct tss16 tss16;
- memset(&tss16, 0, sizeof(tss16));
- tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16;
- tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0;
- tss16.ip = ADDR_VAR_USER_CODE2;
- tss16.flags = (1 << 1);
- tss16.cs = SEL_CS16;
- tss16.es = tss16.ds = tss16.ss = SEL_DS16;
- tss16.ldt = SEL_LDT;
- struct tss16* tss16_addr = (struct tss16*)(host_mem + seg_tss16_2.base);
- NONFAILING(memcpy(tss16_addr, &tss16, sizeof(tss16)));
-
- memset(&tss16, 0, sizeof(tss16));
- tss16.ss0 = tss16.ss1 = tss16.ss2 = SEL_DS16;
- tss16.sp0 = tss16.sp1 = tss16.sp2 = ADDR_STACK0;
- tss16.ip = ADDR_VAR_USER_CODE2;
- tss16.flags = (1 << 1);
- tss16.cs = SEL_CS16_CPL3;
- tss16.es = tss16.ds = tss16.ss = SEL_DS16_CPL3;
- tss16.ldt = SEL_LDT;
- struct tss16* tss16_cpl3_addr = (struct tss16*)(host_mem + seg_tss16_cpl3.base);
- NONFAILING(memcpy(tss16_cpl3_addr, &tss16, sizeof(tss16)));
-
- struct tss32 tss32;
- memset(&tss32, 0, sizeof(tss32));
- tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32;
- tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0;
- tss32.ip = ADDR_VAR_USER_CODE;
- tss32.flags = (1 << 1) | (1 << 17);
- tss32.ldt = SEL_LDT;
- tss32.cr3 = sregs.cr3;
- tss32.io_bitmap = offsetof(struct tss32, io_bitmap);
- struct tss32* tss32_addr = (struct tss32*)(host_mem + seg_tss32_vm86.base);
- NONFAILING(memcpy(tss32_addr, &tss32, sizeof(tss32)));
-
- memset(&tss32, 0, sizeof(tss32));
- tss32.ss0 = tss32.ss1 = tss32.ss2 = SEL_DS32;
- tss32.sp0 = tss32.sp1 = tss32.sp2 = ADDR_STACK0;
- tss32.ip = ADDR_VAR_USER_CODE;
- tss32.flags = (1 << 1);
- tss32.cr3 = sregs.cr3;
- tss32.es = tss32.ds = tss32.ss = tss32.gs = tss32.fs = SEL_DS32;
- tss32.cs = SEL_CS32;
- tss32.ldt = SEL_LDT;
- tss32.cr3 = sregs.cr3;
- tss32.io_bitmap = offsetof(struct tss32, io_bitmap);
- struct tss32* tss32_cpl3_addr = (struct tss32*)(host_mem + seg_tss32_2.base);
- NONFAILING(memcpy(tss32_cpl3_addr, &tss32, sizeof(tss32)));
-
- struct tss64 tss64;
- memset(&tss64, 0, sizeof(tss64));
- tss64.rsp[0] = ADDR_STACK0;
- tss64.rsp[1] = ADDR_STACK0;
- tss64.rsp[2] = ADDR_STACK0;
- tss64.io_bitmap = offsetof(struct tss64, io_bitmap);
- struct tss64* tss64_addr = (struct tss64*)(host_mem + seg_tss64.base);
- NONFAILING(memcpy(tss64_addr, &tss64, sizeof(tss64)));
-
- memset(&tss64, 0, sizeof(tss64));
- tss64.rsp[0] = ADDR_STACK0;
- tss64.rsp[1] = ADDR_STACK0;
- tss64.rsp[2] = ADDR_STACK0;
- tss64.io_bitmap = offsetof(struct tss64, io_bitmap);
- struct tss64* tss64_cpl3_addr = (struct tss64*)(host_mem + seg_tss64_cpl3.base);
- NONFAILING(memcpy(tss64_cpl3_addr, &tss64, sizeof(tss64)));
-
- if (text_size > 1000)
- text_size = 1000;
- if (text_prefix) {
- NONFAILING(memcpy(host_text, text_prefix, text_prefix_size));
- void* patch = 0;
- NONFAILING(patch = memmem(host_text, text_prefix_size, "\xde\xc0\xad\x0b", 4));
- if (patch)
- NONFAILING(*((uint32*)patch) = guest_mem + ADDR_TEXT + ((char*)patch - host_text) + 6);
- uint16 magic = PREFIX_SIZE;
- patch = 0;
- NONFAILING(patch = memmem(host_text, text_prefix_size, &magic, sizeof(magic)));
- if (patch)
- NONFAILING(*((uint16*)patch) = guest_mem + ADDR_TEXT + text_prefix_size);
- }
- NONFAILING(memcpy((void*)(host_text + text_prefix_size), text, text_size));
- NONFAILING(*(host_text + text_prefix_size + text_size) = 0xf4);
-
- NONFAILING(memcpy(host_mem + ADDR_VAR_USER_CODE, text, text_size));
- NONFAILING(*(host_mem + ADDR_VAR_USER_CODE + text_size) = 0xf4);
-
- NONFAILING(*(host_mem + ADDR_VAR_HLT) = 0xf4);
- NONFAILING(memcpy(host_mem + ADDR_VAR_SYSRET, "\x0f\x07\xf4", 3));
- NONFAILING(memcpy(host_mem + ADDR_VAR_SYSEXIT, "\x0f\x35\xf4", 3));
-
- NONFAILING(*(uint64*)(host_mem + ADDR_VAR_VMWRITE_FLD) = 0);
- NONFAILING(*(uint64*)(host_mem + ADDR_VAR_VMWRITE_VAL) = 0);
-
- if (opt_count > 2)
- opt_count = 2;
- for (i = 0; i < opt_count; i++) {
- uint64 typ = 0;
- uint64 val = 0;
- NONFAILING(typ = opt_array_ptr[i].typ);
- NONFAILING(val = opt_array_ptr[i].val);
- switch (typ % 9) {
- case 0:
- sregs.cr0 ^= val & (CR0_MP | CR0_EM | CR0_ET | CR0_NE | CR0_WP | CR0_AM | CR0_NW | CR0_CD);
- break;
- case 1:
- sregs.cr4 ^= val & (CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PGE | CR4_PCE |
- CR4_OSFXSR | CR4_OSXMMEXCPT | CR4_UMIP | CR4_VMXE | CR4_SMXE | CR4_FSGSBASE | CR4_PCIDE |
- CR4_OSXSAVE | CR4_SMEP | CR4_SMAP | CR4_PKE);
- break;
- case 2:
- sregs.efer ^= val & (EFER_SCE | EFER_NXE | EFER_SVME | EFER_LMSLE | EFER_FFXSR | EFER_TCE);
- break;
- case 3:
- val &= ((1 << 8) | (1 << 9) | (1 << 10) | (1 << 12) | (1 << 13) | (1 << 14) |
- (1 << 15) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21));
- regs.rflags ^= val;
- NONFAILING(tss16_addr->flags ^= val);
- NONFAILING(tss16_cpl3_addr->flags ^= val);
- NONFAILING(tss32_addr->flags ^= val);
- NONFAILING(tss32_cpl3_addr->flags ^= val);
- break;
- case 4:
- seg_cs16.type = val & 0xf;
- seg_cs32.type = val & 0xf;
- seg_cs64.type = val & 0xf;
- break;
- case 5:
- seg_cs16_cpl3.type = val & 0xf;
- seg_cs32_cpl3.type = val & 0xf;
- seg_cs64_cpl3.type = val & 0xf;
- break;
- case 6:
- seg_ds16.type = val & 0xf;
- seg_ds32.type = val & 0xf;
- seg_ds64.type = val & 0xf;
- break;
- case 7:
- seg_ds16_cpl3.type = val & 0xf;
- seg_ds32_cpl3.type = val & 0xf;
- seg_ds64_cpl3.type = val & 0xf;
- break;
- case 8:
- NONFAILING(*(uint64*)(host_mem + ADDR_VAR_VMWRITE_FLD) = (val & 0xffff));
- NONFAILING(*(uint64*)(host_mem + ADDR_VAR_VMWRITE_VAL) = (val >> 16));
- break;
- default:
- fail("bad kvm setup opt");
- }
- }
- regs.rflags |= 2;
-
- fill_segment_descriptor(gdt, ldt, &seg_ldt);
- fill_segment_descriptor(gdt, ldt, &seg_cs16);
- fill_segment_descriptor(gdt, ldt, &seg_ds16);
- fill_segment_descriptor(gdt, ldt, &seg_cs16_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_ds16_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_cs32);
- fill_segment_descriptor(gdt, ldt, &seg_ds32);
- fill_segment_descriptor(gdt, ldt, &seg_cs32_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_ds32_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_cs64);
- fill_segment_descriptor(gdt, ldt, &seg_ds64);
- fill_segment_descriptor(gdt, ldt, &seg_cs64_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_ds64_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_tss32);
- fill_segment_descriptor(gdt, ldt, &seg_tss32_2);
- fill_segment_descriptor(gdt, ldt, &seg_tss32_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_tss32_vm86);
- fill_segment_descriptor(gdt, ldt, &seg_tss16);
- fill_segment_descriptor(gdt, ldt, &seg_tss16_2);
- fill_segment_descriptor(gdt, ldt, &seg_tss16_cpl3);
- fill_segment_descriptor_dword(gdt, ldt, &seg_tss64);
- fill_segment_descriptor_dword(gdt, ldt, &seg_tss64_cpl3);
- fill_segment_descriptor(gdt, ldt, &seg_cgate16);
- fill_segment_descriptor(gdt, ldt, &seg_tgate16);
- fill_segment_descriptor(gdt, ldt, &seg_cgate32);
- fill_segment_descriptor(gdt, ldt, &seg_tgate32);
- fill_segment_descriptor_dword(gdt, ldt, &seg_cgate64);
-
- if (ioctl(cpufd, KVM_SET_SREGS, &sregs))
- return -1;
- if (ioctl(cpufd, KVM_SET_REGS, &regs))
- return -1;
- return 0;
-}
-#elif defined(__aarch64__)
-
-
-
-struct kvm_text {
- uintptr_t typ;
- const void* text;
- uintptr_t size;
-};
-
-struct kvm_opt {
- uint64 typ;
- uint64 val;
-};
-
-static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7)
-{
- const int vmfd = a0;
- const int cpufd = a1;
- char* const host_mem = (char*)a2;
- const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3;
- const uintptr_t text_count = a4;
- const uintptr_t flags = a5;
- const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6;
- uintptr_t opt_count = a7;
-
- (void)flags;
- (void)opt_count;
-
- const uintptr_t page_size = 4 << 10;
- const uintptr_t guest_mem = 0;
- const uintptr_t guest_mem_size = 24 * page_size;
-
- (void)text_count;
- int text_type = 0;
- const void* text = 0;
- int text_size = 0;
- NONFAILING(text_type = text_array_ptr[0].typ);
- NONFAILING(text = text_array_ptr[0].text);
- NONFAILING(text_size = text_array_ptr[0].size);
- (void)text_type;
- (void)opt_array_ptr;
-
- uint32 features = 0;
- if (opt_count > 1)
- opt_count = 1;
- uintptr_t i;
- for (i = 0; i < opt_count; i++) {
- uint64 typ = 0;
- uint64 val = 0;
- NONFAILING(typ = opt_array_ptr[i].typ);
- NONFAILING(val = opt_array_ptr[i].val);
- switch (typ) {
- case 1:
- features = val;
- break;
- }
- }
-
- for (i = 0; i < guest_mem_size / page_size; i++) {
- struct kvm_userspace_memory_region memreg;
- memreg.slot = i;
- memreg.flags = 0;
- memreg.guest_phys_addr = guest_mem + i * page_size;
- memreg.memory_size = page_size;
- memreg.userspace_addr = (uintptr_t)host_mem + i * page_size;
- ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
- }
-
- struct kvm_vcpu_init init;
- ioctl(cpufd, KVM_ARM_PREFERRED_TARGET, &init);
- init.features[0] = features;
- ioctl(cpufd, KVM_ARM_VCPU_INIT, &init);
-
- if (text_size > 1000)
- text_size = 1000;
- NONFAILING(memcpy(host_mem, text, text_size));
-
- return 0;
-}
-#else
-static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7)
-{
- return 0;
-}
-#endif
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION) || defined(SYZ_SANDBOX_NAMESPACE) || \
- defined(SYZ_ENABLE_CGROUPS)
-static bool write_file(const char* file, const char* what, ...)
-{
- char buf[1024];
- va_list args;
- va_start(args, what);
- vsnprintf(buf, sizeof(buf), what, args);
- va_end(args);
- buf[sizeof(buf) - 1] = 0;
- int len = strlen(buf);
-
- int fd = open(file, O_WRONLY | O_CLOEXEC);
- if (fd == -1)
- return false;
- if (write(fd, buf, len) != len) {
- int err = errno;
- close(fd);
- errno = err;
- return false;
- }
- close(fd);
- return true;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
-static void setup_cgroups()
-{
- if (mkdir("/syzcgroup", 0777)) {
- debug("mkdir(/syzcgroup) failed: %d\n", errno);
- }
- if (mkdir("/syzcgroup/unified", 0777)) {
- debug("mkdir(/syzcgroup/unified) failed: %d\n", errno);
- }
- if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
- debug("mount(cgroup2) failed: %d\n", errno);
- }
- if (chmod("/syzcgroup/unified", 0777)) {
- debug("chmod(/syzcgroup/unified) failed: %d\n", errno);
- }
- if (!write_file("/syzcgroup/unified/cgroup.subtree_control", "+cpu +memory +io +pids +rdma")) {
- debug("write(cgroup.subtree_control) failed: %d\n", errno);
- }
- if (mkdir("/syzcgroup/cpu", 0777)) {
- debug("mkdir(/syzcgroup/cpu) failed: %d\n", errno);
- }
- if (mount("none", "/syzcgroup/cpu", "cgroup", 0, "cpuset,cpuacct,perf_event,hugetlb")) {
- debug("mount(cgroup cpu) failed: %d\n", errno);
- }
- if (!write_file("/syzcgroup/cpu/cgroup.clone_children", "1")) {
- debug("write(/syzcgroup/cpu/cgroup.clone_children) failed: %d\n", errno);
- }
- if (chmod("/syzcgroup/cpu", 0777)) {
- debug("chmod(/syzcgroup/cpu) failed: %d\n", errno);
- }
- if (mkdir("/syzcgroup/net", 0777)) {
- debug("mkdir(/syzcgroup/net) failed: %d\n", errno);
- }
- if (mount("none", "/syzcgroup/net", "cgroup", 0, "net_cls,net_prio,devices,freezer")) {
- debug("mount(cgroup net) failed: %d\n", errno);
- }
- if (chmod("/syzcgroup/net", 0777)) {
- debug("chmod(/syzcgroup/net) failed: %d\n", errno);
- }
-}
-
-static void setup_binfmt_misc()
-{
- if (!write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:syz0::./file0:")) {
- debug("write(/proc/sys/fs/binfmt_misc/register, syz0) failed: %d\n", errno);
- }
- if (!write_file("/proc/sys/fs/binfmt_misc/register", ":syz1:M:1:yz1::./file0:POC")) {
- debug("write(/proc/sys/fs/binfmt_misc/register, syz1) failed: %d\n", errno);
- }
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE)
-static void loop();
-
-static void sandbox_common()
-{
- prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
- setpgrp();
- setsid();
-
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_init_net_socket)
- int netns = open("/proc/self/ns/net", O_RDONLY);
- if (netns == -1)
- fail("open(/proc/self/ns/net) failed");
- if (dup2(netns, kInitNetNsFd) < 0)
- fail("dup2(netns, kInitNetNsFd) failed");
- close(netns);
-#endif
-
- struct rlimit rlim;
- rlim.rlim_cur = rlim.rlim_max = 160 << 20;
- setrlimit(RLIMIT_AS, &rlim);
- rlim.rlim_cur = rlim.rlim_max = 8 << 20;
- setrlimit(RLIMIT_MEMLOCK, &rlim);
- rlim.rlim_cur = rlim.rlim_max = 136 << 20;
- setrlimit(RLIMIT_FSIZE, &rlim);
- rlim.rlim_cur = rlim.rlim_max = 1 << 20;
- setrlimit(RLIMIT_STACK, &rlim);
- rlim.rlim_cur = rlim.rlim_max = 0;
- setrlimit(RLIMIT_CORE, &rlim);
-
- if (unshare(CLONE_NEWNS)) {
- debug("unshare(CLONE_NEWNS): %d\n", errno);
- }
- if (unshare(CLONE_NEWIPC)) {
- debug("unshare(CLONE_NEWIPC): %d\n", errno);
- }
- if (unshare(0x02000000)) {
- debug("unshare(CLONE_NEWCGROUP): %d\n", errno);
- }
- if (unshare(CLONE_NEWUTS)) {
- debug("unshare(CLONE_NEWUTS): %d\n", errno);
- }
- if (unshare(CLONE_SYSVSEM)) {
- debug("unshare(CLONE_SYSVSEM): %d\n", errno);
- }
-}
-
-int wait_for_loop(int pid)
-{
- if (pid < 0)
- fail("sandbox fork failed");
- debug("spawned loop pid %d\n", pid);
- int status = 0;
- while (waitpid(-1, &status, __WALL) != pid) {
- }
- return WEXITSTATUS(status);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE)
-static int do_sandbox_none(void)
-{
- if (unshare(CLONE_NEWPID)) {
- debug("unshare(CLONE_NEWPID): %d\n", errno);
- }
- int pid = fork();
- if (pid != 0)
- return wait_for_loop(pid);
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
- setup_cgroups();
- setup_binfmt_misc();
-#endif
- sandbox_common();
- if (unshare(CLONE_NEWNET)) {
- debug("unshare(CLONE_NEWNET): %d\n", errno);
- }
-#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE)
- initialize_tun();
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_NETDEV)
- initialize_netdevices();
-#endif
- loop();
- doexit(1);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_SETUID)
-static int do_sandbox_setuid(void)
-{
- if (unshare(CLONE_NEWPID))
- fail("unshare(CLONE_NEWPID)");
- int pid = fork();
- if (pid != 0)
- return wait_for_loop(pid);
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
- setup_cgroups();
- setup_binfmt_misc();
-#endif
- sandbox_common();
- if (unshare(CLONE_NEWNET))
- fail("unshare(CLONE_NEWNET)");
-#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE)
- initialize_tun();
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_NETDEV)
- initialize_netdevices();
-#endif
-
- const int nobody = 65534;
- if (setgroups(0, NULL))
- fail("failed to setgroups");
- if (syscall(SYS_setresgid, nobody, nobody, nobody))
- fail("failed to setresgid");
- if (syscall(SYS_setresuid, nobody, nobody, nobody))
- fail("failed to setresuid");
-
- prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-
- loop();
- doexit(1);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NAMESPACE)
-static int real_uid;
-static int real_gid;
-__attribute__((aligned(64 << 10))) static char sandbox_stack[1 << 20];
-
-static int namespace_sandbox_proc(void* arg)
-{
- sandbox_common();
-
- write_file("/proc/self/setgroups", "deny");
- if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid))
- fail("write of /proc/self/uid_map failed");
- if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid))
- fail("write of /proc/self/gid_map failed");
-
- if (unshare(CLONE_NEWNET))
- fail("unshare(CLONE_NEWNET)");
-#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE)
- initialize_tun();
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_NETDEV)
- initialize_netdevices();
-#endif
-
- if (mkdir("./syz-tmp", 0777))
- fail("mkdir(syz-tmp) failed");
- if (mount("", "./syz-tmp", "tmpfs", 0, NULL))
- fail("mount(tmpfs) failed");
- if (mkdir("./syz-tmp/newroot", 0777))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/dev", 0700))
- fail("mkdir failed");
- unsigned mount_flags = MS_BIND | MS_REC | MS_PRIVATE;
- if (mount("/dev", "./syz-tmp/newroot/dev", NULL, mount_flags, NULL))
- fail("mount(dev) failed");
- if (mkdir("./syz-tmp/newroot/proc", 0700))
- fail("mkdir failed");
- if (mount(NULL, "./syz-tmp/newroot/proc", "proc", 0, NULL))
- fail("mount(proc) failed");
- if (mkdir("./syz-tmp/newroot/selinux", 0700))
- fail("mkdir failed");
- const char* selinux_path = "./syz-tmp/newroot/selinux";
- if (mount("/selinux", selinux_path, NULL, mount_flags, NULL)) {
- if (errno != ENOENT)
- fail("mount(/selinux) failed");
- if (mount("/sys/fs/selinux", selinux_path, NULL, mount_flags, NULL) && errno != ENOENT)
- fail("mount(/sys/fs/selinux) failed");
- }
- if (mkdir("./syz-tmp/newroot/sys", 0700))
- fail("mkdir failed");
- if (mount(NULL, "./syz-tmp/newroot/sys", "sysfs", 0, NULL))
- fail("mount(sysfs) failed");
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
- if (mkdir("./syz-tmp/newroot/syzcgroup", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/unified", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/cpu", 0700))
- fail("mkdir failed");
- if (mkdir("./syz-tmp/newroot/syzcgroup/net", 0700))
- fail("mkdir failed");
- if (mount("/syzcgroup/unified", "./syz-tmp/newroot/syzcgroup/unified", NULL, mount_flags, NULL)) {
- debug("mount(cgroup2, MS_BIND) failed: %d\n", errno);
- }
- if (mount("/syzcgroup/cpu", "./syz-tmp/newroot/syzcgroup/cpu", NULL, mount_flags, NULL)) {
- debug("mount(cgroup/cpu, MS_BIND) failed: %d\n", errno);
- }
- if (mount("/syzcgroup/net", "./syz-tmp/newroot/syzcgroup/net", NULL, mount_flags, NULL)) {
- debug("mount(cgroup/net, MS_BIND) failed: %d\n", errno);
- }
-#endif
- if (mkdir("./syz-tmp/pivot", 0777))
- fail("mkdir failed");
- if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) {
- debug("pivot_root failed\n");
- if (chdir("./syz-tmp"))
- fail("chdir failed");
- } else {
- debug("pivot_root OK\n");
- if (chdir("/"))
- fail("chdir failed");
- if (umount2("./pivot", MNT_DETACH))
- fail("umount failed");
- }
- if (chroot("./newroot"))
- fail("chroot failed");
- if (chdir("/"))
- fail("chdir failed");
-
- struct __user_cap_header_struct cap_hdr = {};
- struct __user_cap_data_struct cap_data[2] = {};
- cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
- cap_hdr.pid = getpid();
- if (syscall(SYS_capget, &cap_hdr, &cap_data))
- fail("capget failed");
- cap_data[0].effective &= ~(1 << CAP_SYS_PTRACE);
- cap_data[0].permitted &= ~(1 << CAP_SYS_PTRACE);
- cap_data[0].inheritable &= ~(1 << CAP_SYS_PTRACE);
- if (syscall(SYS_capset, &cap_hdr, &cap_data))
- fail("capset failed");
-
- loop();
- doexit(1);
-}
-
-static int do_sandbox_namespace(void)
-{
- int pid;
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
- setup_cgroups();
- setup_binfmt_misc();
-#endif
- real_uid = getuid();
- real_gid = getgid();
- mprotect(sandbox_stack, 4096, PROT_NONE);
- pid = clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 64],
- CLONE_NEWUSER | CLONE_NEWPID, 0);
- return wait_for_loop(pid);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE)
-
-#define XT_TABLE_SIZE 1536
-#define XT_MAX_ENTRIES 10
-
-struct xt_counters {
- uint64 pcnt, bcnt;
-};
-
-struct ipt_getinfo {
- char name[32];
- unsigned int valid_hooks;
- unsigned int hook_entry[5];
- unsigned int underflow[5];
- unsigned int num_entries;
- unsigned int size;
-};
-
-struct ipt_get_entries {
- char name[32];
- unsigned int size;
- void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
-};
-
-struct ipt_replace {
- char name[32];
- unsigned int valid_hooks;
- unsigned int num_entries;
- unsigned int size;
- unsigned int hook_entry[5];
- unsigned int underflow[5];
- unsigned int num_counters;
- struct xt_counters* counters;
- char entrytable[XT_TABLE_SIZE];
-};
-
-struct ipt_table_desc {
- const char* name;
- struct ipt_getinfo info;
- struct ipt_replace replace;
-};
-
-static struct ipt_table_desc ipv4_tables[] = {
- {.name = "filter"},
- {.name = "nat"},
- {.name = "mangle"},
- {.name = "raw"},
- {.name = "security"},
-};
-
-static struct ipt_table_desc ipv6_tables[] = {
- {.name = "filter"},
- {.name = "nat"},
- {.name = "mangle"},
- {.name = "raw"},
- {.name = "security"},
-};
-
-#define IPT_BASE_CTL 64
-#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
-#define IPT_SO_GET_INFO (IPT_BASE_CTL)
-#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
-
-struct arpt_getinfo {
- char name[32];
- unsigned int valid_hooks;
- unsigned int hook_entry[3];
- unsigned int underflow[3];
- unsigned int num_entries;
- unsigned int size;
-};
-
-struct arpt_get_entries {
- char name[32];
- unsigned int size;
- void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
-};
-
-struct arpt_replace {
- char name[32];
- unsigned int valid_hooks;
- unsigned int num_entries;
- unsigned int size;
- unsigned int hook_entry[3];
- unsigned int underflow[3];
- unsigned int num_counters;
- struct xt_counters* counters;
- char entrytable[XT_TABLE_SIZE];
-};
-
-struct arpt_table_desc {
- const char* name;
- struct arpt_getinfo info;
- struct arpt_replace replace;
-};
-
-static struct arpt_table_desc arpt_tables[] = {
- {.name = "filter"},
-};
-
-#define ARPT_BASE_CTL 96
-#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
-#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
-#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
-
-static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables, int family, int level)
-{
- struct ipt_get_entries entries;
- socklen_t optlen;
- int fd, i;
-
- fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
- if (fd == -1) {
- switch (errno) {
- case EAFNOSUPPORT:
- case ENOPROTOOPT:
- return;
- }
- fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family);
- }
- for (i = 0; i < num_tables; i++) {
- struct ipt_table_desc* table = &tables[i];
- strcpy(table->info.name, table->name);
- strcpy(table->replace.name, table->name);
- optlen = sizeof(table->info);
- if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
- switch (errno) {
- case EPERM:
- case ENOENT:
- case ENOPROTOOPT:
- continue;
- }
- fail("getsockopt(IPT_SO_GET_INFO)");
- }
- debug("checkpoint iptable %s/%d: entries=%d hooks=%x size=%d\n", table->name, family, table->info.num_entries, table->info.valid_hooks, table->info.size);
- if (table->info.size > sizeof(table->replace.entrytable))
- fail("table size is too large: %u", table->info.size);
- if (table->info.num_entries > XT_MAX_ENTRIES)
- fail("too many counters: %u", table->info.num_entries);
- memset(&entries, 0, sizeof(entries));
- strcpy(entries.name, table->name);
- entries.size = table->info.size;
- optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
- if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("getsockopt(IPT_SO_GET_ENTRIES)");
- table->replace.valid_hooks = table->info.valid_hooks;
- table->replace.num_entries = table->info.num_entries;
- table->replace.size = table->info.size;
- memcpy(table->replace.hook_entry, table->info.hook_entry, sizeof(table->replace.hook_entry));
- memcpy(table->replace.underflow, table->info.underflow, sizeof(table->replace.underflow));
- memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
- }
- close(fd);
-}
-
-static void reset_iptables(struct ipt_table_desc* tables, int num_tables, int family, int level)
-{
- struct xt_counters counters[XT_MAX_ENTRIES];
- struct ipt_get_entries entries;
- struct ipt_getinfo info;
- socklen_t optlen;
- int fd, i;
-
- fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
- if (fd == -1) {
- switch (errno) {
- case EAFNOSUPPORT:
- case ENOPROTOOPT:
- return;
- }
- fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family);
- }
- for (i = 0; i < num_tables; i++) {
- struct ipt_table_desc* table = &tables[i];
- if (table->info.valid_hooks == 0)
- continue;
- memset(&info, 0, sizeof(info));
- strcpy(info.name, table->name);
- optlen = sizeof(info);
- if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
- fail("getsockopt(IPT_SO_GET_INFO)");
- if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
- memset(&entries, 0, sizeof(entries));
- strcpy(entries.name, table->name);
- entries.size = table->info.size;
- optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
- if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("getsockopt(IPT_SO_GET_ENTRIES)");
- if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0)
- continue;
- }
- debug("resetting iptable %s\n", table->name);
- table->replace.num_counters = info.num_entries;
- table->replace.counters = counters;
- optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size;
- if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
- fail("setsockopt(IPT_SO_SET_REPLACE)");
- }
- close(fd);
-}
-
-static void checkpoint_arptables(void)
-{
- struct arpt_get_entries entries;
- socklen_t optlen;
- unsigned i;
- int fd;
-
- fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (fd == -1) {
- switch (errno) {
- case EAFNOSUPPORT:
- case ENOPROTOOPT:
- return;
- }
- fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
- }
- for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
- struct arpt_table_desc* table = &arpt_tables[i];
- strcpy(table->info.name, table->name);
- strcpy(table->replace.name, table->name);
- optlen = sizeof(table->info);
- if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
- switch (errno) {
- case EPERM:
- case ENOENT:
- case ENOPROTOOPT:
- continue;
- }
- fail("getsockopt(ARPT_SO_GET_INFO)");
- }
- debug("checkpoint arptable %s: entries=%d hooks=%x size=%d\n", table->name, table->info.num_entries, table->info.valid_hooks, table->info.size);
- if (table->info.size > sizeof(table->replace.entrytable))
- fail("table size is too large: %u", table->info.size);
- if (table->info.num_entries > XT_MAX_ENTRIES)
- fail("too many counters: %u", table->info.num_entries);
- memset(&entries, 0, sizeof(entries));
- strcpy(entries.name, table->name);
- entries.size = table->info.size;
- optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
- if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("getsockopt(ARPT_SO_GET_ENTRIES)");
- table->replace.valid_hooks = table->info.valid_hooks;
- table->replace.num_entries = table->info.num_entries;
- table->replace.size = table->info.size;
- memcpy(table->replace.hook_entry, table->info.hook_entry, sizeof(table->replace.hook_entry));
- memcpy(table->replace.underflow, table->info.underflow, sizeof(table->replace.underflow));
- memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
- }
- close(fd);
-}
-
-static void reset_arptables()
-{
- struct xt_counters counters[XT_MAX_ENTRIES];
- struct arpt_get_entries entries;
- struct arpt_getinfo info;
- socklen_t optlen;
- unsigned i;
- int fd;
-
- fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (fd == -1) {
- switch (errno) {
- case EAFNOSUPPORT:
- case ENOPROTOOPT:
- return;
- }
- fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
- }
- for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
- struct arpt_table_desc* table = &arpt_tables[i];
- if (table->info.valid_hooks == 0)
- continue;
- memset(&info, 0, sizeof(info));
- strcpy(info.name, table->name);
- optlen = sizeof(info);
- if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
- fail("getsockopt(ARPT_SO_GET_INFO)");
- if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
- memset(&entries, 0, sizeof(entries));
- strcpy(entries.name, table->name);
- entries.size = table->info.size;
- optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
- if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
- fail("getsockopt(ARPT_SO_GET_ENTRIES)");
- if (memcmp(table->replace.entrytable, entries.entrytable, table->info.size) == 0)
- continue;
- }
- debug("resetting arptable %s\n", table->name);
- table->replace.num_counters = info.num_entries;
- table->replace.counters = counters;
- optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) + table->replace.size;
- if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
- fail("setsockopt(ARPT_SO_SET_REPLACE)");
- }
- close(fd);
-}
-
-#include <linux/if.h>
-#include <linux/netfilter_bridge/ebtables.h>
-
-struct ebt_table_desc {
- const char* name;
- struct ebt_replace replace;
- char entrytable[XT_TABLE_SIZE];
-};
-
-static struct ebt_table_desc ebt_tables[] = {
- {.name = "filter"},
- {.name = "nat"},
- {.name = "broute"},
-};
-
-static void checkpoint_ebtables(void)
-{
- socklen_t optlen;
- unsigned i;
- int fd;
-
- fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (fd == -1) {
- switch (errno) {
- case EAFNOSUPPORT:
- case ENOPROTOOPT:
- return;
- }
- fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
- }
- for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
- struct ebt_table_desc* table = &ebt_tables[i];
- strcpy(table->replace.name, table->name);
- optlen = sizeof(table->replace);
- if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace, &optlen)) {
- switch (errno) {
- case EPERM:
- case ENOENT:
- case ENOPROTOOPT:
- continue;
- }
- fail("getsockopt(EBT_SO_GET_INIT_INFO)");
- }
- debug("checkpoint ebtable %s: entries=%d hooks=%x size=%d\n", table->name, table->replace.nentries, table->replace.valid_hooks, table->replace.entries_size);
- if (table->replace.entries_size > sizeof(table->entrytable))
- fail("table size is too large: %u", table->replace.entries_size);
- table->replace.num_counters = 0;
- table->replace.entries = table->entrytable;
- optlen = sizeof(table->replace) + table->replace.entries_size;
- if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace, &optlen))
- fail("getsockopt(EBT_SO_GET_INIT_ENTRIES)");
- }
- close(fd);
-}
-
-static void reset_ebtables()
-{
- struct ebt_replace replace;
- char entrytable[XT_TABLE_SIZE];
- socklen_t optlen;
- unsigned i, j, h;
- int fd;
-
- fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (fd == -1) {
- switch (errno) {
- case EAFNOSUPPORT:
- case ENOPROTOOPT:
- return;
- }
- fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
- }
- for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
- struct ebt_table_desc* table = &ebt_tables[i];
- if (table->replace.valid_hooks == 0)
- continue;
- memset(&replace, 0, sizeof(replace));
- strcpy(replace.name, table->name);
- optlen = sizeof(replace);
- if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
- fail("getsockopt(EBT_SO_GET_INFO)");
- replace.num_counters = 0;
- table->replace.entries = 0;
- for (h = 0; h < NF_BR_NUMHOOKS; h++)
- table->replace.hook_entry[h] = 0;
- if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
- memset(&entrytable, 0, sizeof(entrytable));
- replace.entries = entrytable;
- optlen = sizeof(replace) + replace.entries_size;
- if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
- fail("getsockopt(EBT_SO_GET_ENTRIES)");
- if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
- continue;
- }
- debug("resetting ebtable %s\n", table->name);
- for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
- if (table->replace.valid_hooks & (1 << h)) {
- table->replace.hook_entry[h] = (struct ebt_entries*)table->entrytable + j;
- j++;
- }
- }
- table->replace.entries = table->entrytable;
- optlen = sizeof(table->replace) + table->replace.entries_size;
- if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
- fail("setsockopt(EBT_SO_SET_ENTRIES)");
- }
- close(fd);
-}
-
-static void checkpoint_net_namespace(void)
-{
- checkpoint_ebtables();
- checkpoint_arptables();
- checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP);
- checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6);
-}
-
-static void reset_net_namespace(void)
-{
- reset_ebtables();
- reset_arptables();
- reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]), AF_INET, SOL_IP);
- reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]), AF_INET6, SOL_IPV6);
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT) && defined(SYZ_USE_TMP_DIR))
-static void remove_dir(const char* dir)
-{
- DIR* dp;
- struct dirent* ep;
- int iter = 0;
-retry:
- while (umount2(dir, MNT_DETACH) == 0) {
- debug("umount(%s)\n", dir);
- }
- dp = opendir(dir);
- if (dp == NULL) {
- if (errno == EMFILE) {
- exitf("opendir(%s) failed due to NOFILE, exiting", dir);
- }
- exitf("opendir(%s) failed", dir);
- }
- while ((ep = readdir(dp))) {
- if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
- continue;
- char filename[FILENAME_MAX];
- snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
- while (umount2(filename, MNT_DETACH) == 0) {
- debug("umount(%s)\n", filename);
- }
- struct stat st;
- if (lstat(filename, &st))
- exitf("lstat(%s) failed", filename);
- if (S_ISDIR(st.st_mode)) {
- remove_dir(filename);
- continue;
- }
- int i;
- for (i = 0;; i++) {
- debug("unlink(%s)\n", filename);
- if (unlink(filename) == 0)
- break;
- if (errno == EROFS) {
- debug("ignoring EROFS\n");
- break;
- }
- if (errno != EBUSY || i > 100)
- exitf("unlink(%s) failed", filename);
- debug("umount(%s)\n", filename);
- if (umount2(filename, MNT_DETACH))
- exitf("umount(%s) failed", filename);
- }
- }
- closedir(dp);
- int i;
- for (i = 0;; i++) {
- debug("rmdir(%s)\n", dir);
- if (rmdir(dir) == 0)
- break;
- if (i < 100) {
- if (errno == EROFS) {
- debug("ignoring EROFS\n");
- break;
- }
- if (errno == EBUSY) {
- debug("umount(%s)\n", dir);
- if (umount2(dir, MNT_DETACH))
- exitf("umount(%s) failed", dir);
- continue;
- }
- if (errno == ENOTEMPTY) {
- if (iter < 100) {
- iter++;
- goto retry;
- }
- }
- }
- exitf("rmdir(%s) failed", dir);
- }
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_FAULT_INJECTION)
-static int inject_fault(int nth)
-{
- int fd;
- char buf[16];
-
- fd = open("/proc/thread-self/fail-nth", O_RDWR);
- if (fd == -1)
- exitf("failed to open /proc/thread-self/fail-nth");
- sprintf(buf, "%d", nth + 1);
- if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
- exitf("failed to write /proc/thread-self/fail-nth");
- return fd;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR)
-static int fault_injected(int fail_fd)
-{
- char buf[16];
- int n = read(fail_fd, buf, sizeof(buf) - 1);
- if (n <= 0)
- exitf("failed to read /proc/thread-self/fail-nth");
- int res = n == 2 && buf[0] == '0' && buf[1] == '\n';
- buf[0] = '0';
- if (write(fail_fd, buf, 1) != 1)
- exitf("failed to write /proc/thread-self/fail-nth");
- close(fail_fd);
- return res;
-}
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_REPEAT)
-static void execute_one();
-extern unsigned long long procid;
-
-#if defined(SYZ_EXECUTOR)
-void reply_handshake();
-void receive_execute();
-void reply_execute(int status);
-extern uint32* output_data;
-extern uint32* output_pos;
-#endif
-
-#if defined(SYZ_EXECUTOR) || defined(SYZ_WAIT_REPEAT)
-static void loop()
-{
-#if defined(SYZ_EXECUTOR)
- reply_handshake();
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE)
- checkpoint_net_namespace();
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
- char cgroupdir[64];
- snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
- char cgroupdir_cpu[64];
- snprintf(cgroupdir_cpu, sizeof(cgroupdir_cpu), "/syzcgroup/cpu/syz%llu", procid);
- char cgroupdir_net[64];
- snprintf(cgroupdir_net, sizeof(cgroupdir_net), "/syzcgroup/net/syz%llu", procid);
- if (mkdir(cgroupdir, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir, errno);
- }
- if (mkdir(cgroupdir_cpu, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir_cpu, errno);
- }
- if (mkdir(cgroupdir_net, 0777)) {
- debug("mkdir(%s) failed: %d\n", cgroupdir_net, errno);
- }
- int pid = getpid();
- char procs_file[128];
- snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir);
- if (!write_file(procs_file, "%d", pid)) {
- debug("write(%s) failed: %d\n", procs_file, errno);
- }
- snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir_cpu);
- if (!write_file(procs_file, "%d", pid)) {
- debug("write(%s) failed: %d\n", procs_file, errno);
- }
- snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir_net);
- if (!write_file(procs_file, "%d", pid)) {
- debug("write(%s) failed: %d\n", procs_file, errno);
- }
-#endif
- int iter;
- for (iter = 0;; iter++) {
-#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
- char cwdbuf[32];
- sprintf(cwdbuf, "./%d", iter);
- if (mkdir(cwdbuf, 0777))
- fail("failed to mkdir");
-#endif
-#if defined(SYZ_EXECUTOR) || defined(__NR_syz_mount_image) || defined(__NR_syz_read_part_table)
- char buf[64];
- snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
- int loopfd = open(buf, O_RDWR);
- if (loopfd != -1) {
- ioctl(loopfd, LOOP_CLR_FD, 0);
- close(loopfd);
- }
-#endif
-#if defined(SYZ_EXECUTOR)
- receive_execute();
-#endif
- int pid = fork();
- if (pid < 0)
- fail("clone failed");
- if (pid == 0) {
- prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
- setpgrp();
-#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
- if (chdir(cwdbuf))
- fail("failed to chdir");
-#endif
-#if defined(SYZ_EXECUTOR)
- close(kInPipeFd);
- close(kOutPipeFd);
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_ENABLE_CGROUPS)
- if (symlink(cgroupdir, "./cgroup")) {
- debug("symlink(%s, ./cgroup) failed: %d\n", cgroupdir, errno);
- }
- if (symlink(cgroupdir_cpu, "./cgroup.cpu")) {
- debug("symlink(%s, ./cgroup.cpu) failed: %d\n", cgroupdir_cpu, errno);
- }
- if (symlink(cgroupdir_net, "./cgroup.net")) {
- debug("symlink(%s, ./cgroup.net) failed: %d\n", cgroupdir_net, errno);
- }
-#endif
-#if defined(SYZ_EXECUTOR)
- if (flag_enable_tun) {
- flush_tun();
- }
- output_pos = output_data;
-#elif defined(SYZ_TUN_ENABLE)
- flush_tun();
-#endif
- execute_one();
- debug("worker exiting\n");
- int fd;
- for (fd = 3; fd < 30; fd++)
- close(fd);
- doexit(0);
- }
- debug("spawned worker pid %d\n", pid);
-
- int status = 0;
- uint64 start = current_time_ms();
-#if defined(SYZ_EXECUTOR)
- uint64 last_executed = start;
- uint32 executed_calls = __atomic_load_n(output_data, __ATOMIC_RELAXED);
-#endif
- for (;;) {
- int res = waitpid(-1, &status, __WALL | WNOHANG);
- if (res == pid) {
- debug("waitpid(%d)=%d\n", pid, res);
- break;
- }
- usleep(1000);
-#if defined(SYZ_EXECUTOR)
- uint64 now = current_time_ms();
- uint32 now_executed = __atomic_load_n(output_data, __ATOMIC_RELAXED);
- if (executed_calls != now_executed) {
- executed_calls = now_executed;
- last_executed = now;
- }
- if ((now - start < 5 * 1000) && (now - start < 3000 || now - last_executed < 1000))
- continue;
-#else
- if (current_time_ms() - start < 5 * 1000)
- continue;
-#endif
- debug("waitpid(%d)=%d\n", pid, res);
- debug("killing\n");
- kill(-pid, SIGKILL);
- kill(pid, SIGKILL);
- while (waitpid(-1, &status, __WALL) != pid) {
- }
- break;
- }
-#if defined(SYZ_EXECUTOR)
- status = WEXITSTATUS(status);
- if (status == kFailStatus)
- fail("child failed");
- if (status == kErrorStatus)
- error("child errored");
- reply_execute(0);
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_USE_TMP_DIR)
- remove_dir(cwdbuf);
-#endif
-#if defined(SYZ_EXECUTOR) || defined(SYZ_RESET_NET_NAMESPACE)
- reset_net_namespace();
-#endif
- }
-}
-#else
-void loop()
-{
- while (1) {
- execute_one();
- }
-}
-#endif
-#endif
-
-#if defined(SYZ_THREADED)
-struct thread_t {
- int created, running, call;
- pthread_t th;
-};
-
-static struct thread_t threads[16];
-static void execute_call(int call);
-static int running;
-#if defined(SYZ_COLLIDE)
-static int collide;
-#endif
-
-static void* thr(void* arg)
-{
- struct thread_t* th = (struct thread_t*)arg;
- for (;;) {
- while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
- syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
- execute_call(th->call);
- __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
- __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
- syscall(SYS_futex, &th->running, FUTEX_WAKE);
- }
- return 0;
-}
-
-static void execute(int num_calls)
-{
- int call, thread;
- running = 0;
- for (call = 0; call < num_calls; call++) {
- for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
- struct thread_t* th = &threads[thread];
- if (!th->created) {
- th->created = 1;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, 128 << 10);
- pthread_create(&th->th, &attr, thr, th);
- }
- if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
- th->call = call;
- __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
- __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
- syscall(SYS_futex, &th->running, FUTEX_WAKE);
-#if defined(SYZ_COLLIDE)
- if (collide && call % 2)
- break;
-#endif
- struct timespec ts;
- ts.tv_sec = 0;
- ts.tv_nsec = 20 * 1000 * 1000;
- syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
- if (__atomic_load_n(&running, __ATOMIC_RELAXED))
- usleep((call == num_calls - 1) ? 10000 : 1000);
- break;
- }
- }
- }
-}
-#endif
-`