github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/common.h (about)

     1  // Copyright 2016 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  // This file is shared between executor and csource package.
     5  // csource does a bunch of transformations with this file:
     6  // - unused parts are stripped using #if SYZ* defines
     7  // - includes are hoisted to the top and deduplicated
     8  // - comments and empty lines are stripped
     9  // - NORETURN/PRINTF/debug are removed
    10  // - exitf/fail are replaced with exit
    11  // - uintN types are replaced with uintN_t
    12  // - /*{{{FOO}}}*/ placeholders are replaced by actual values
    13  
    14  #ifndef _GNU_SOURCE
    15  #define _GNU_SOURCE
    16  #endif
    17  
    18  #if GOOS_freebsd || GOOS_test && HOSTGOOS_freebsd
    19  #include <sys/endian.h> // for htobe*.
    20  #elif GOOS_darwin
    21  #include <libkern/OSByteOrder.h>
    22  #define htobe16(x) OSSwapHostToBigInt16(x)
    23  #define htobe32(x) OSSwapHostToBigInt32(x)
    24  #define htobe64(x) OSSwapHostToBigInt64(x)
    25  #define le16toh(x) OSSwapLittleToHostInt16(x)
    26  #define htole16(x) OSSwapHostToLittleInt16(x)
    27  #elif GOOS_windows
    28  #define htobe16 _byteswap_ushort
    29  #define htobe32 _byteswap_ulong
    30  #define htobe64 _byteswap_uint64
    31  #define le16toh(x) x
    32  #define htole16(x) x
    33  typedef signed int ssize_t;
    34  #else
    35  #include <endian.h> // for htobe*.
    36  #endif
    37  #include <stdint.h>
    38  #include <stdio.h> // for fmt arguments
    39  #include <stdlib.h>
    40  #include <string.h>
    41  
    42  #if SYZ_TRACE
    43  #include <errno.h>
    44  #endif
    45  
    46  #if !SYZ_EXECUTOR
    47  /*{{{SYSCALL_DEFINES}}}*/
    48  #endif
    49  
    50  #if SYZ_EXECUTOR && !GOOS_linux
    51  #if !GOOS_windows
    52  #include <unistd.h>
    53  #endif
    54  NORETURN void doexit(int status)
    55  {
    56  	_exit(status); // prevent linter warning: doexit()
    57  	for (;;) {
    58  	}
    59  }
    60  #if !GOOS_fuchsia
    61  NORETURN void doexit_thread(int status)
    62  {
    63  	// For BSD systems, _exit seems to do exactly what's needed.
    64  	doexit(status);
    65  }
    66  #endif
    67  #endif
    68  
    69  #if SYZ_EXECUTOR || SYZ_MULTI_PROC || SYZ_REPEAT && SYZ_CGROUPS ||                      \
    70      SYZ_NET_DEVICES || __NR_syz_mount_image || __NR_syz_read_part_table ||              \
    71      __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_usbip_server_init || \
    72      (GOOS_freebsd || GOOS_darwin || GOOS_openbsd || GOOS_netbsd) && SYZ_NET_INJECTION
    73  static unsigned long long procid;
    74  #endif
    75  
    76  #if !GOOS_fuchsia && !GOOS_windows
    77  #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
    78  #include <setjmp.h>
    79  #include <signal.h>
    80  #include <string.h>
    81  
    82  #if GOOS_linux
    83  #include <sys/syscall.h>
    84  #endif
    85  
    86  static __thread int clone_ongoing;
    87  static __thread int skip_segv;
    88  static __thread jmp_buf segv_env;
    89  
    90  static void segv_handler(int sig, siginfo_t* info, void* ctx)
    91  {
    92  	// Generated programs can contain bad (unmapped/protected) addresses,
    93  	// which cause SIGSEGVs during copyin/copyout.
    94  	// This handler ignores such crashes to allow the program to proceed.
    95  	// We additionally opportunistically check that the faulty address
    96  	// is not within executable data region, because such accesses can corrupt
    97  	// output region and then fuzzer will fail on corrupted data.
    98  
    99  	if (__atomic_load_n(&clone_ongoing, __ATOMIC_RELAXED) != 0) {
   100  		// During clone, we always exit on a SEGV. If we do not, then
   101  		// it might prevent us from running child-specific code. E.g.
   102  		// if an invalid stack is passed to the clone() call, then it
   103  		// will trigger a seg fault, which in turn causes the child to
   104  		// jump over the NONFAILING macro and continue execution in
   105  		// parallel with the parent.
   106  		doexit_thread(sig);
   107  	}
   108  
   109  	uintptr_t addr = (uintptr_t)info->si_addr;
   110  	const uintptr_t prog_start = 1 << 20;
   111  	const uintptr_t prog_end = 100 << 20;
   112  	int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0;
   113  	int valid = addr < prog_start || addr > prog_end;
   114  #if GOOS_freebsd || (GOOS_test && HOSTGOOS_freebsd)
   115  	// FreeBSD delivers SIGBUS in response to any fault that isn't a page
   116  	// fault.  In this case it tries to be helpful and sets si_addr to the
   117  	// address of the faulting instruction rather than zero as other
   118  	// operating systems seem to do.  However, such faults should always be
   119  	// ignored.
   120  	if (sig == SIGBUS)
   121  		valid = 1;
   122  #endif
   123  	if (skip && valid) {
   124  		debug("SIGSEGV on %p, skipping\n", (void*)addr);
   125  		_longjmp(segv_env, 1);
   126  	}
   127  	debug("SIGSEGV on %p, exiting\n", (void*)addr);
   128  	doexit(sig);
   129  }
   130  
   131  static void install_segv_handler(void)
   132  {
   133  	struct sigaction sa;
   134  #if GOOS_linux
   135  	// Don't need that SIGCANCEL/SIGSETXID glibc stuff.
   136  	// SIGCANCEL sent to main thread causes it to exit
   137  	// without bringing down the whole group.
   138  	memset(&sa, 0, sizeof(sa));
   139  	sa.sa_handler = SIG_IGN;
   140  	syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
   141  	syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
   142  #endif
   143  	memset(&sa, 0, sizeof(sa));
   144  	sa.sa_sigaction = segv_handler;
   145  	sa.sa_flags = SA_NODEFER | SA_SIGINFO;
   146  	sigaction(SIGSEGV, &sa, NULL);
   147  	sigaction(SIGBUS, &sa, NULL);
   148  }
   149  
   150  #define NONFAILING(...)                                              \
   151  	({                                                           \
   152  		int ok = 1;                                          \
   153  		__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
   154  		if (_setjmp(segv_env) == 0) {                        \
   155  			__VA_ARGS__;                                 \
   156  		} else                                               \
   157  			ok = 0;                                      \
   158  		__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
   159  		ok;                                                  \
   160  	})
   161  #endif
   162  #endif
   163  
   164  #if !GOOS_linux
   165  #if (SYZ_EXECUTOR || SYZ_REPEAT) && SYZ_EXECUTOR_USES_FORK_SERVER
   166  #include <signal.h>
   167  #include <sys/types.h>
   168  #include <sys/wait.h>
   169  
   170  static void kill_and_wait(int pid, int* status)
   171  {
   172  	kill(pid, SIGKILL);
   173  	while (waitpid(-1, status, 0) != pid) {
   174  	}
   175  }
   176  #endif
   177  #endif
   178  
   179  #if !GOOS_windows
   180  #if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER || \
   181      __NR_syz_usb_connect || __NR_syz_usb_connect_ath9k || __NR_syz_sleep_ms ||     \
   182      __NR_syz_usb_control_io || __NR_syz_usb_ep_read || __NR_syz_usb_ep_write ||    \
   183      __NR_syz_usb_disconnect
   184  static void sleep_ms(uint64 ms)
   185  {
   186  	usleep(ms * 1000);
   187  }
   188  #endif
   189  
   190  #if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER || \
   191      SYZ_LEAK
   192  #include <time.h>
   193  
   194  static uint64 current_time_ms(void)
   195  {
   196  	struct timespec ts;
   197  	if (clock_gettime(CLOCK_MONOTONIC, &ts))
   198  		fail("clock_gettime failed");
   199  	return (uint64)ts.tv_sec * 1000 + (uint64)ts.tv_nsec / 1000000;
   200  }
   201  #endif
   202  
   203  #if SYZ_EXECUTOR || SYZ_SANDBOX_ANDROID || SYZ_USE_TMP_DIR
   204  #include <stdlib.h>
   205  #include <sys/stat.h>
   206  #include <unistd.h>
   207  
   208  static void use_temporary_dir(void)
   209  {
   210  #if SYZ_SANDBOX_ANDROID
   211  	char tmpdir_template[] = "/data/local/tmp/syzkaller.XXXXXX";
   212  #elif GOOS_fuchsia
   213  	char tmpdir_template[] = "/tmp/syzkaller.XXXXXX";
   214  #else
   215  	char tmpdir_template[] = "./syzkaller.XXXXXX";
   216  #endif
   217  	char* tmpdir = mkdtemp(tmpdir_template);
   218  	if (!tmpdir)
   219  		fail("failed to mkdtemp");
   220  	if (chmod(tmpdir, 0777))
   221  		fail("failed to chmod");
   222  	if (chdir(tmpdir))
   223  		fail("failed to chdir");
   224  }
   225  #endif
   226  #endif
   227  
   228  #if GOOS_netbsd || GOOS_freebsd || GOOS_darwin || GOOS_openbsd || GOOS_test
   229  #if SYZ_EXECUTOR || SYZ_REPEAT && SYZ_USE_TMP_DIR && SYZ_EXECUTOR_USES_FORK_SERVER
   230  #include <dirent.h>
   231  #include <errno.h>
   232  #include <stdio.h>
   233  #include <string.h>
   234  #include <sys/stat.h>
   235  #include <sys/types.h>
   236  
   237  #if GOOS_freebsd
   238  // Unset file flags which might inhibit unlinking.
   239  static void reset_flags(const char* filename)
   240  {
   241  	struct stat st;
   242  	if (lstat(filename, &st))
   243  		exitf("lstat(%s) failed", filename);
   244  	st.st_flags &= ~(SF_NOUNLINK | UF_NOUNLINK | SF_IMMUTABLE | UF_IMMUTABLE | SF_APPEND | UF_APPEND);
   245  	if (lchflags(filename, st.st_flags))
   246  		exitf("lchflags(%s) failed", filename);
   247  }
   248  #endif
   249  
   250  // We need to prevent the compiler from unrolling the while loop by using the gcc's noinline attribute
   251  // because otherwise it could trigger the compiler warning about a potential format truncation
   252  // when a filename is constructed with help of snprintf. This warning occurs because by unrolling
   253  // the while loop, the snprintf call will try to concatenate 2 buffers of length FILENAME_MAX and put
   254  // the result into a buffer of length FILENAME_MAX which is apparently not possible. But this is no
   255  // problem in our case because file and directory names should be short enough and fit into a buffer
   256  // of length FILENAME_MAX.
   257  static void __attribute__((noinline)) remove_dir(const char* dir)
   258  {
   259  	DIR* dp = opendir(dir);
   260  	if (dp == NULL) {
   261  		if (errno == EACCES) {
   262  			// We could end up here in a recursive call to remove_dir() below.
   263  			// One of executed syscall could end up creating a directory rooted
   264  			// in the current working directory created by loop() with zero
   265  			// permissions. Try to perform a best effort removal of the
   266  			// directory.
   267  			if (rmdir(dir))
   268  				exitf("rmdir(%s) failed", dir);
   269  			return;
   270  		}
   271  		exitf("opendir(%s) failed", dir);
   272  	}
   273  	struct dirent* ep = 0;
   274  	while ((ep = readdir(dp))) {
   275  		if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
   276  			continue;
   277  		char filename[FILENAME_MAX];
   278  		snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
   279  		struct stat st;
   280  		if (lstat(filename, &st))
   281  			exitf("lstat(%s) failed", filename);
   282  		if (S_ISDIR(st.st_mode)) {
   283  			remove_dir(filename);
   284  			continue;
   285  		}
   286  		if (unlink(filename)) {
   287  #if GOOS_freebsd
   288  			if (errno == EPERM) {
   289  				reset_flags(filename);
   290  				reset_flags(dir);
   291  				if (unlink(filename) == 0)
   292  					continue;
   293  			}
   294  #endif
   295  			exitf("unlink(%s) failed", filename);
   296  		}
   297  	}
   298  	closedir(dp);
   299  	while (rmdir(dir)) {
   300  #if GOOS_freebsd
   301  		if (errno == EPERM) {
   302  			reset_flags(dir);
   303  			if (rmdir(dir) == 0)
   304  				break;
   305  		}
   306  #endif
   307  		exitf("rmdir(%s) failed", dir);
   308  	}
   309  }
   310  #endif
   311  #endif
   312  
   313  #if !GOOS_linux && !GOOS_netbsd
   314  #if SYZ_EXECUTOR || SYZ_FAULT
   315  static int inject_fault(int nth)
   316  {
   317  	return 0;
   318  }
   319  #endif
   320  
   321  #if SYZ_FAULT
   322  static const char* setup_fault()
   323  {
   324  	return NULL;
   325  }
   326  #endif
   327  
   328  #if SYZ_EXECUTOR
   329  static int fault_injected(int fail_fd)
   330  {
   331  	return 0;
   332  }
   333  #endif
   334  #endif
   335  
   336  #if !GOOS_windows
   337  #if SYZ_EXECUTOR || SYZ_THREADED
   338  #include <errno.h>
   339  #include <pthread.h>
   340  
   341  static void thread_start(void* (*fn)(void*), void* arg)
   342  {
   343  	pthread_t th;
   344  	pthread_attr_t attr;
   345  	pthread_attr_init(&attr);
   346  	pthread_attr_setstacksize(&attr, 128 << 10);
   347  	// Clone can fail spuriously with EAGAIN if there is a concurrent execve in progress.
   348  	// (see linux kernel commit 498052bba55ec). But it can also be a true limit imposed by cgroups.
   349  	// In one case we want to retry infinitely, in another -- fail immidiately...
   350  	int i = 0;
   351  	for (; i < 100; i++) {
   352  		if (pthread_create(&th, &attr, fn, arg) == 0) {
   353  			pthread_attr_destroy(&attr);
   354  			return;
   355  		}
   356  		if (errno == EAGAIN) {
   357  			usleep(50);
   358  			continue;
   359  		}
   360  		break;
   361  	}
   362  	exitf("pthread_create failed");
   363  }
   364  
   365  #endif
   366  #endif
   367  
   368  #if GOOS_freebsd || GOOS_darwin || GOOS_netbsd || GOOS_openbsd || GOOS_test
   369  #if SYZ_EXECUTOR || SYZ_THREADED
   370  
   371  #include <pthread.h>
   372  #include <time.h>
   373  
   374  typedef struct {
   375  	pthread_mutex_t mu;
   376  	pthread_cond_t cv;
   377  	int state;
   378  } event_t;
   379  
   380  static void event_init(event_t* ev)
   381  {
   382  	if (pthread_mutex_init(&ev->mu, 0))
   383  		exitf("pthread_mutex_init failed");
   384  	if (pthread_cond_init(&ev->cv, 0))
   385  		exitf("pthread_cond_init failed");
   386  	ev->state = 0;
   387  }
   388  
   389  static void event_reset(event_t* ev)
   390  {
   391  	ev->state = 0;
   392  }
   393  
   394  static void event_set(event_t* ev)
   395  {
   396  	pthread_mutex_lock(&ev->mu);
   397  	if (ev->state)
   398  		exitf("event already set");
   399  	ev->state = 1;
   400  	pthread_mutex_unlock(&ev->mu);
   401  	pthread_cond_broadcast(&ev->cv);
   402  }
   403  
   404  static void event_wait(event_t* ev)
   405  {
   406  	pthread_mutex_lock(&ev->mu);
   407  	while (!ev->state)
   408  		pthread_cond_wait(&ev->cv, &ev->mu);
   409  	pthread_mutex_unlock(&ev->mu);
   410  }
   411  
   412  static int event_isset(event_t* ev)
   413  {
   414  	pthread_mutex_lock(&ev->mu);
   415  	int res = ev->state;
   416  	pthread_mutex_unlock(&ev->mu);
   417  	return res;
   418  }
   419  
   420  static int event_timedwait(event_t* ev, uint64 timeout)
   421  {
   422  	uint64 start = current_time_ms();
   423  	uint64 now = start;
   424  	pthread_mutex_lock(&ev->mu);
   425  	for (;;) {
   426  		if (ev->state)
   427  			break;
   428  		uint64 remain = timeout - (now - start);
   429  		struct timespec ts;
   430  		ts.tv_sec = remain / 1000;
   431  		ts.tv_nsec = (remain % 1000) * 1000 * 1000;
   432  		pthread_cond_timedwait(&ev->cv, &ev->mu, &ts);
   433  		now = current_time_ms();
   434  		if (now - start > timeout)
   435  			break;
   436  	}
   437  	int res = ev->state;
   438  	pthread_mutex_unlock(&ev->mu);
   439  	return res;
   440  }
   441  #endif
   442  #endif
   443  
   444  #if SYZ_EXECUTOR || SYZ_USE_BITMASKS
   445  #define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
   446  #define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len)                        \
   447  	*(type*)(addr) = htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \
   448  			       (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
   449  #endif
   450  
   451  #if SYZ_EXECUTOR || SYZ_USE_CHECKSUMS
   452  struct csum_inet {
   453  	uint32 acc;
   454  };
   455  
   456  static void csum_inet_init(struct csum_inet* csum)
   457  {
   458  	csum->acc = 0;
   459  }
   460  
   461  static void csum_inet_update(struct csum_inet* csum, const uint8* data, size_t length)
   462  {
   463  	if (length == 0)
   464  		return;
   465  
   466  	size_t i = 0;
   467  	for (; i < length - 1; i += 2)
   468  		csum->acc += *(uint16*)&data[i];
   469  
   470  	if (length & 1)
   471  		csum->acc += le16toh((uint16)data[length - 1]);
   472  
   473  	while (csum->acc > 0xffff)
   474  		csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16);
   475  }
   476  
   477  static uint16 csum_inet_digest(struct csum_inet* csum)
   478  {
   479  	return ~csum->acc;
   480  }
   481  #endif
   482  
   483  #if GOOS_freebsd || GOOS_darwin || GOOS_netbsd
   484  #include "common_bsd.h"
   485  #elif GOOS_openbsd
   486  #include "common_openbsd.h"
   487  #elif GOOS_fuchsia
   488  #include "common_fuchsia.h"
   489  #elif GOOS_linux
   490  #include "common_linux.h"
   491  #elif GOOS_test
   492  #include "common_test.h"
   493  #elif GOOS_windows
   494  #include "common_windows.h"
   495  #else
   496  #error "unknown OS"
   497  #endif
   498  
   499  #if SYZ_TEST_COMMON_EXT_EXAMPLE
   500  #include "common_ext_example.h"
   501  #else
   502  #include "common_ext.h"
   503  #endif
   504  
   505  #if SYZ_EXECUTOR || __NR_syz_execute_func
   506  // syz_execute_func(text ptr[in, text[taget]])
   507  static long syz_execute_func(volatile long text)
   508  {
   509  	// Here we just to random code which is inherently unsafe.
   510  	// But we only care about coverage in the output region.
   511  	// The following code tries to remove left-over pointers in registers
   512  	// from the reach of the random code, otherwise it's known to reach
   513  	// the output region somehow. The asm block is arch-independent except
   514  	// for the number of available registers.
   515  #if defined(__GNUC__)
   516  	volatile long p[8] = {0};
   517  	(void)p;
   518  #if GOARCH_amd64
   519  	asm volatile("" ::"r"(0l), "r"(1l), "r"(2l), "r"(3l), "r"(4l), "r"(5l), "r"(6l),
   520  		     "r"(7l), "r"(8l), "r"(9l), "r"(10l), "r"(11l), "r"(12l), "r"(13l));
   521  #endif
   522  #endif
   523  	((void (*)(void))(text))();
   524  	return 0;
   525  }
   526  #endif
   527  
   528  #if SYZ_THREADED
   529  struct thread_t {
   530  	int created, call;
   531  	event_t ready, done;
   532  };
   533  
   534  static struct thread_t threads[16];
   535  static void execute_call(int call);
   536  static int running;
   537  
   538  static void* thr(void* arg)
   539  {
   540  	struct thread_t* th = (struct thread_t*)arg;
   541  	for (;;) {
   542  		event_wait(&th->ready);
   543  		event_reset(&th->ready);
   544  		execute_call(th->call);
   545  		__atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
   546  		event_set(&th->done);
   547  	}
   548  	return 0;
   549  }
   550  
   551  #if SYZ_REPEAT
   552  static void execute_one(void)
   553  #else
   554  static void loop(void)
   555  #endif
   556  {
   557  	if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
   558  	}
   559  #if SYZ_TRACE
   560  	fprintf(stderr, "### start\n");
   561  #endif
   562  	int i, call, thread;
   563  	for (call = 0; call < /*{{{NUM_CALLS}}}*/; call++) {
   564  		for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) {
   565  			struct thread_t* th = &threads[thread];
   566  			if (!th->created) {
   567  				th->created = 1;
   568  				event_init(&th->ready);
   569  				event_init(&th->done);
   570  				event_set(&th->done);
   571  				thread_start(thr, th);
   572  			}
   573  			if (!event_isset(&th->done))
   574  				continue;
   575  			event_reset(&th->done);
   576  			th->call = call;
   577  			__atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
   578  			event_set(&th->ready);
   579  #if SYZ_ASYNC
   580  			if (/*{{{ASYNC_CONDITIONS}}}*/)
   581  				break;
   582  #endif
   583  			event_timedwait(&th->done, /*{{{CALL_TIMEOUT_MS}}}*/);
   584  			break;
   585  		}
   586  	}
   587  	for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
   588  		sleep_ms(1);
   589  #if SYZ_HAVE_CLOSE_FDS
   590  	close_fds();
   591  #endif
   592  }
   593  #endif
   594  
   595  #if SYZ_EXECUTOR || SYZ_REPEAT
   596  static void execute_one(void);
   597  
   598  #if GOOS_linux
   599  #define WAIT_FLAGS __WALL
   600  #else
   601  #define WAIT_FLAGS 0
   602  #endif
   603  
   604  #if SYZ_EXECUTOR_USES_FORK_SERVER
   605  #include <signal.h>
   606  #include <sys/types.h>
   607  #include <sys/wait.h>
   608  
   609  static void loop(void)
   610  {
   611  #if SYZ_HAVE_SETUP_LOOP
   612  	setup_loop();
   613  #endif
   614  #if SYZ_EXECUTOR
   615  	// Tell parent that we are ready to serve.
   616  	if (!flag_snapshot)
   617  		reply_execute(0);
   618  #endif
   619  	int iter = 0;
   620  #if SYZ_REPEAT_TIMES
   621  	for (; iter < /*{{{REPEAT_TIMES}}}*/; iter++) {
   622  #else
   623  	for (;; iter++) {
   624  #endif
   625  #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
   626  		// Create a new private work dir for this test (removed at the end of the loop).
   627  		char cwdbuf[32];
   628  		sprintf(cwdbuf, "./%d", iter);
   629  		if (mkdir(cwdbuf, 0777))
   630  			fail("failed to mkdir");
   631  #endif
   632  #if SYZ_HAVE_RESET_LOOP
   633  		reset_loop();
   634  #endif
   635  #if SYZ_EXECUTOR
   636  		if (!flag_snapshot)
   637  			receive_execute();
   638  #endif
   639  		int pid = fork();
   640  		if (pid < 0)
   641  			fail("clone failed");
   642  		if (pid == 0) {
   643  #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
   644  			if (chdir(cwdbuf))
   645  				fail("failed to chdir");
   646  #endif
   647  #if SYZ_HAVE_SETUP_TEST
   648  			setup_test();
   649  #endif
   650  #if SYZ_HAVE_SETUP_EXT_TEST
   651  			setup_ext_test();
   652  #endif
   653  #if SYZ_EXECUTOR
   654  			close(kInPipeFd);
   655  #endif
   656  #if SYZ_EXECUTOR
   657  			close(kOutPipeFd);
   658  #endif
   659  			execute_one();
   660  #if !SYZ_EXECUTOR && SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED
   661  			// Executor's execute_one has already called close_fds.
   662  			close_fds();
   663  #endif
   664  			doexit(0);
   665  		}
   666  		debug("spawned worker pid %d\n", pid);
   667  
   668  #if SYZ_EXECUTOR
   669  		if (flag_snapshot)
   670  			SnapshotPrepareParent();
   671  #endif
   672  
   673  		// We used to use sigtimedwait(SIGCHLD) to wait for the subprocess.
   674  		// But SIGCHLD is also delivered when a process stops/continues,
   675  		// so it would require a loop with status analysis and timeout recalculation.
   676  		// SIGCHLD should also unblock the usleep below, so the spin loop
   677  		// should be as efficient as sigtimedwait.
   678  		int status = 0;
   679  		uint64 start = current_time_ms();
   680  #if SYZ_EXECUTOR
   681  		uint64 last_executed = start;
   682  		uint32 executed_calls = output_data->completed.load(std::memory_order_relaxed);
   683  #endif
   684  		for (;;) {
   685  			sleep_ms(10);
   686  			if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
   687  				break;
   688  #if SYZ_EXECUTOR
   689  			// Even though the test process executes exit at the end
   690  			// and execution time of each syscall is bounded by syscall_timeout_ms (~50ms),
   691  			// this backup watchdog is necessary and its performance is important.
   692  			// The problem is that exit in the test processes can fail (sic).
   693  			// One observed scenario is that the test processes prohibits
   694  			// exit_group syscall using seccomp. Another observed scenario
   695  			// is that the test processes setups a userfaultfd for itself,
   696  			// then the main thread hangs when it wants to page in a page.
   697  			// Below we check if the test process still executes syscalls
   698  			// and kill it after ~1s of inactivity.
   699  			// (Globs are an exception: they can be slow, so we allow up to ~120s)
   700  			uint64 min_timeout_ms = program_timeout_ms * 3 / 5;
   701  			uint64 inactive_timeout_ms = syscall_timeout_ms * 20;
   702  			uint64 glob_timeout_ms = program_timeout_ms * 120;
   703  
   704  			uint64 now = current_time_ms();
   705  			uint32 now_executed = output_data->completed.load(std::memory_order_relaxed);
   706  			if (executed_calls != now_executed) {
   707  				executed_calls = now_executed;
   708  				last_executed = now;
   709  			}
   710  
   711  			// TODO: adjust timeout for progs with syz_usb_connect call.
   712  			// If the max program timeout is exceeded, kill unconditionally.
   713  			if ((now - start > program_timeout_ms && request_type != rpc::RequestType::Glob) || (now - start > glob_timeout_ms && request_type == rpc::RequestType::Glob))
   714  				goto kill_test;
   715  			// If the request type is not a normal test program (currently, glob expansion request),
   716  			// then wait for the full timeout (these requests don't update number of completed calls
   717  			// + they are more important and we don't want timing flakes).
   718  			if (request_type != rpc::RequestType::Program)
   719  				continue;
   720  			// Always wait at least the min timeout for each program.
   721  			if (now - start < min_timeout_ms)
   722  				continue;
   723  			// If it keeps completing syscalls, then don't kill it.
   724  			if (now - last_executed < inactive_timeout_ms)
   725  				continue;
   726  		kill_test:
   727  #else
   728  			if (current_time_ms() - start < /*{{{PROGRAM_TIMEOUT_MS}}}*/)
   729  				continue;
   730  #endif
   731  			debug("killing hanging pid %d\n", pid);
   732  			kill_and_wait(pid, &status);
   733  			break;
   734  		}
   735  #if SYZ_EXECUTOR
   736  		if (WEXITSTATUS(status) == kFailStatus) {
   737  			errno = 0;
   738  			fail("child failed");
   739  		}
   740  		reply_execute(0);
   741  #endif
   742  #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR
   743  		remove_dir(cwdbuf);
   744  #endif
   745  #if SYZ_LEAK
   746  		// Note: this will fail under setuid sandbox because we don't have
   747  		// write permissions for the kmemleak file.
   748  		check_leaks();
   749  #endif
   750  	}
   751  }
   752  #else
   753  static void loop(void)
   754  {
   755  	execute_one();
   756  }
   757  #endif
   758  #endif
   759  
   760  #if !SYZ_EXECUTOR
   761  
   762  /*{{{RESULTS}}}*/
   763  
   764  #if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID
   765  #if SYZ_THREADED
   766  void execute_call(int call)
   767  #elif SYZ_REPEAT
   768  void execute_one(void)
   769  #else
   770  void loop(void)
   771  #endif
   772  {
   773  	/*{{{SYSCALLS}}}*/
   774  #if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT
   775  	close_fds();
   776  #endif
   777  }
   778  #endif
   779  
   780  // This is the main function for csource.
   781  int main(void)
   782  {
   783  	/*{{{MMAP_DATA}}}*/
   784  
   785  #if SYZ_SYSCTL
   786  	setup_sysctl();
   787  #endif
   788  #if SYZ_CGROUPS
   789  	setup_cgroups();
   790  #endif
   791  	const char* reason;
   792  	(void)reason;
   793  #if SYZ_BINFMT_MISC
   794  	if ((reason = setup_binfmt_misc()))
   795  		printf("the reproducer may not work as expected: binfmt_misc setup failed: %s\n", reason);
   796  #endif
   797  #if SYZ_LEAK
   798  	if ((reason = setup_leak()))
   799  		printf("the reproducer may not work as expected: leak checking setup failed: %s\n", reason);
   800  #endif
   801  #if SYZ_FAULT
   802  	if ((reason = setup_fault()))
   803  		printf("the reproducer may not work as expected: fault injection setup failed: %s\n", reason);
   804  #endif
   805  #if SYZ_KCSAN
   806  	if ((reason = setup_kcsan()))
   807  		printf("the reproducer may not work as expected: KCSAN setup failed: %s\n", reason);
   808  #endif
   809  #if SYZ_USB
   810  	if ((reason = setup_usb()))
   811  		printf("the reproducer may not work as expected: USB injection setup failed: %s\n", reason);
   812  #endif
   813  #if SYZ_802154
   814  	if ((reason = setup_802154()))
   815  		printf("the reproducer may not work as expected: 802154 injection setup failed: %s\n", reason);
   816  #endif
   817  #if SYZ_SWAP
   818  	if ((reason = setup_swap()))
   819  		printf("the reproducer may not work as expected: swap setup failed: %s\n", reason);
   820  #endif
   821  #if SYZ_HANDLE_SEGV
   822  	install_segv_handler();
   823  #endif
   824  #if SYZ_HAVE_SETUP_EXT
   825  	setup_ext();
   826  #endif
   827  #if SYZ_MULTI_PROC
   828  	for (procid = 0; procid < /*{{{PROCS}}}*/; procid++) {
   829  		if (fork() == 0) {
   830  #endif
   831  #if SYZ_USE_TMP_DIR || SYZ_SANDBOX_ANDROID
   832  			use_temporary_dir();
   833  #endif
   834  			/*{{{SANDBOX_FUNC}}}*/
   835  #if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT && !SYZ_SANDBOX_NONE && \
   836      !SYZ_SANDBOX_SETUID && !SYZ_SANDBOX_NAMESPACE && !SYZ_SANDBOX_ANDROID
   837  			close_fds();
   838  #endif
   839  #if SYZ_MULTI_PROC
   840  		}
   841  	}
   842  	sleep(1000000);
   843  #endif
   844  #if !SYZ_MULTI_PROC && !SYZ_REPEAT && SYZ_LEAK
   845  	check_leaks();
   846  #endif
   847  	return 0;
   848  }
   849  #endif