github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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); 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_EXECUTOR_USES_FORK_SERVER && (SYZ_EXECUTOR || SYZ_USE_TMP_DIR) 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 void setup_fault() 323 { 324 } 325 #endif 326 327 #if SYZ_EXECUTOR 328 static int fault_injected(int fail_fd) 329 { 330 return 0; 331 } 332 #endif 333 #endif 334 335 #if !GOOS_windows 336 #if SYZ_EXECUTOR || SYZ_THREADED 337 #include <errno.h> 338 #include <pthread.h> 339 340 static void thread_start(void* (*fn)(void*), void* arg) 341 { 342 pthread_t th; 343 pthread_attr_t attr; 344 pthread_attr_init(&attr); 345 pthread_attr_setstacksize(&attr, 128 << 10); 346 // Clone can fail spuriously with EAGAIN if there is a concurrent execve in progress. 347 // (see linux kernel commit 498052bba55ec). But it can also be a true limit imposed by cgroups. 348 // In one case we want to retry infinitely, in another -- fail immidiately... 349 int i = 0; 350 for (; i < 100; i++) { 351 if (pthread_create(&th, &attr, fn, arg) == 0) { 352 pthread_attr_destroy(&attr); 353 return; 354 } 355 if (errno == EAGAIN) { 356 usleep(50); 357 continue; 358 } 359 break; 360 } 361 exitf("pthread_create failed"); 362 } 363 364 #endif 365 #endif 366 367 #if GOOS_freebsd || GOOS_darwin || GOOS_netbsd || GOOS_openbsd || GOOS_test 368 #if SYZ_EXECUTOR || SYZ_THREADED 369 370 #include <pthread.h> 371 #include <time.h> 372 373 typedef struct { 374 pthread_mutex_t mu; 375 pthread_cond_t cv; 376 int state; 377 } event_t; 378 379 static void event_init(event_t* ev) 380 { 381 if (pthread_mutex_init(&ev->mu, 0)) 382 exitf("pthread_mutex_init failed"); 383 if (pthread_cond_init(&ev->cv, 0)) 384 exitf("pthread_cond_init failed"); 385 ev->state = 0; 386 } 387 388 static void event_reset(event_t* ev) 389 { 390 ev->state = 0; 391 } 392 393 static void event_set(event_t* ev) 394 { 395 pthread_mutex_lock(&ev->mu); 396 if (ev->state) 397 exitf("event already set"); 398 ev->state = 1; 399 pthread_mutex_unlock(&ev->mu); 400 pthread_cond_broadcast(&ev->cv); 401 } 402 403 static void event_wait(event_t* ev) 404 { 405 pthread_mutex_lock(&ev->mu); 406 while (!ev->state) 407 pthread_cond_wait(&ev->cv, &ev->mu); 408 pthread_mutex_unlock(&ev->mu); 409 } 410 411 static int event_isset(event_t* ev) 412 { 413 pthread_mutex_lock(&ev->mu); 414 int res = ev->state; 415 pthread_mutex_unlock(&ev->mu); 416 return res; 417 } 418 419 static int event_timedwait(event_t* ev, uint64 timeout) 420 { 421 uint64 start = current_time_ms(); 422 uint64 now = start; 423 pthread_mutex_lock(&ev->mu); 424 for (;;) { 425 if (ev->state) 426 break; 427 uint64 remain = timeout - (now - start); 428 struct timespec ts; 429 ts.tv_sec = remain / 1000; 430 ts.tv_nsec = (remain % 1000) * 1000 * 1000; 431 pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); 432 now = current_time_ms(); 433 if (now - start > timeout) 434 break; 435 } 436 int res = ev->state; 437 pthread_mutex_unlock(&ev->mu); 438 return res; 439 } 440 #endif 441 #endif 442 443 #if SYZ_EXECUTOR || SYZ_USE_BITMASKS 444 #define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off)) 445 #define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len) \ 446 *(type*)(addr) = htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) | \ 447 (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len)))) 448 #endif 449 450 #if SYZ_EXECUTOR || SYZ_USE_CHECKSUMS 451 struct csum_inet { 452 uint32 acc; 453 }; 454 455 static void csum_inet_init(struct csum_inet* csum) 456 { 457 csum->acc = 0; 458 } 459 460 static void csum_inet_update(struct csum_inet* csum, const uint8* data, size_t length) 461 { 462 if (length == 0) 463 return; 464 465 size_t i = 0; 466 for (; i < length - 1; i += 2) 467 csum->acc += *(uint16*)&data[i]; 468 469 if (length & 1) 470 csum->acc += le16toh((uint16)data[length - 1]); 471 472 while (csum->acc > 0xffff) 473 csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16); 474 } 475 476 static uint16 csum_inet_digest(struct csum_inet* csum) 477 { 478 return ~csum->acc; 479 } 480 #endif 481 482 #if GOOS_freebsd || GOOS_darwin || GOOS_netbsd 483 #include "common_bsd.h" 484 #elif GOOS_openbsd 485 #include "common_openbsd.h" 486 #elif GOOS_fuchsia 487 #include "common_fuchsia.h" 488 #elif GOOS_linux 489 #include "common_linux.h" 490 #elif GOOS_test 491 #include "common_test.h" 492 #elif GOOS_windows 493 #include "common_windows.h" 494 #else 495 #error "unknown OS" 496 #endif 497 498 #if SYZ_TEST_COMMON_EXT_EXAMPLE 499 #include "common_ext_example.h" 500 #else 501 #include "common_ext.h" 502 #endif 503 504 #if SYZ_EXECUTOR || __NR_syz_execute_func 505 // syz_execute_func(text ptr[in, text[taget]]) 506 static long syz_execute_func(volatile long text) 507 { 508 // Here we just to random code which is inherently unsafe. 509 // But we only care about coverage in the output region. 510 // The following code tries to remove left-over pointers in registers 511 // from the reach of the random code, otherwise it's known to reach 512 // the output region somehow. The asm block is arch-independent except 513 // for the number of available registers. 514 #if defined(__GNUC__) 515 volatile long p[8] = {0}; 516 (void)p; 517 #if GOARCH_amd64 518 asm volatile("" ::"r"(0l), "r"(1l), "r"(2l), "r"(3l), "r"(4l), "r"(5l), "r"(6l), 519 "r"(7l), "r"(8l), "r"(9l), "r"(10l), "r"(11l), "r"(12l), "r"(13l)); 520 #endif 521 #endif 522 ((void (*)(void))(text))(); 523 return 0; 524 } 525 #endif 526 527 #if SYZ_THREADED 528 struct thread_t { 529 int created, call; 530 event_t ready, done; 531 }; 532 533 static struct thread_t threads[16]; 534 static void execute_call(int call); 535 static int running; 536 537 static void* thr(void* arg) 538 { 539 struct thread_t* th = (struct thread_t*)arg; 540 for (;;) { 541 event_wait(&th->ready); 542 event_reset(&th->ready); 543 execute_call(th->call); 544 __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); 545 event_set(&th->done); 546 } 547 return 0; 548 } 549 550 #if SYZ_REPEAT 551 static void execute_one(void) 552 #else 553 static void loop(void) 554 #endif 555 { 556 if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { 557 } 558 #if SYZ_TRACE 559 fprintf(stderr, "### start\n"); 560 #endif 561 int i, call, thread; 562 for (call = 0; call < /*{{{NUM_CALLS}}}*/; call++) { 563 for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); thread++) { 564 struct thread_t* th = &threads[thread]; 565 if (!th->created) { 566 th->created = 1; 567 event_init(&th->ready); 568 event_init(&th->done); 569 event_set(&th->done); 570 thread_start(thr, th); 571 } 572 if (!event_isset(&th->done)) 573 continue; 574 event_reset(&th->done); 575 th->call = call; 576 __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); 577 event_set(&th->ready); 578 #if SYZ_ASYNC 579 if (/*{{{ASYNC_CONDITIONS}}}*/) 580 break; 581 #endif 582 event_timedwait(&th->done, /*{{{CALL_TIMEOUT_MS}}}*/); 583 break; 584 } 585 } 586 for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) 587 sleep_ms(1); 588 #if SYZ_HAVE_CLOSE_FDS 589 close_fds(); 590 #endif 591 } 592 #endif 593 594 #if SYZ_EXECUTOR || SYZ_REPEAT 595 static void execute_one(void); 596 #if SYZ_EXECUTOR_USES_FORK_SERVER 597 #include <signal.h> 598 #include <sys/types.h> 599 #include <sys/wait.h> 600 601 #if GOOS_linux 602 #define WAIT_FLAGS __WALL 603 #else 604 #define WAIT_FLAGS 0 605 #endif 606 607 #if SYZ_EXECUTOR 608 static void reply_handshake(); 609 #endif 610 611 static void loop(void) 612 { 613 #if SYZ_HAVE_SETUP_LOOP 614 setup_loop(); 615 #endif 616 #if SYZ_EXECUTOR 617 // Tell parent that we are ready to serve. 618 reply_handshake(); 619 #endif 620 int iter = 0; 621 #if SYZ_REPEAT_TIMES 622 for (; iter < /*{{{REPEAT_TIMES}}}*/; iter++) { 623 #else 624 for (;; iter++) { 625 #endif 626 #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR 627 // Create a new private work dir for this test (removed at the end of the loop). 628 char cwdbuf[32]; 629 sprintf(cwdbuf, "./%d", iter); 630 if (mkdir(cwdbuf, 0777)) 631 fail("failed to mkdir"); 632 #endif 633 #if SYZ_HAVE_RESET_LOOP 634 reset_loop(); 635 #endif 636 #if SYZ_EXECUTOR 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 && SYZ_EXECUTOR_USES_SHMEM 657 close(kOutPipeFd); 658 #endif 659 execute_one(); 660 #if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED 661 close_fds(); 662 #endif 663 doexit(0); 664 } 665 debug("spawned worker pid %d\n", pid); 666 667 // We used to use sigtimedwait(SIGCHLD) to wait for the subprocess. 668 // But SIGCHLD is also delivered when a process stops/continues, 669 // so it would require a loop with status analysis and timeout recalculation. 670 // SIGCHLD should also unblock the usleep below, so the spin loop 671 // should be as efficient as sigtimedwait. 672 int status = 0; 673 uint64 start = current_time_ms(); 674 #if SYZ_EXECUTOR && SYZ_EXECUTOR_USES_SHMEM 675 uint64 last_executed = start; 676 uint32 executed_calls = __atomic_load_n(output_data, __ATOMIC_RELAXED); 677 #endif 678 for (;;) { 679 if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) 680 break; 681 sleep_ms(1); 682 #if SYZ_EXECUTOR 683 #if SYZ_EXECUTOR_USES_SHMEM 684 // Even though the test process executes exit at the end 685 // and execution time of each syscall is bounded by syscall_timeout_ms (~50ms), 686 // this backup watchdog is necessary and its performance is important. 687 // The problem is that exit in the test processes can fail (sic). 688 // One observed scenario is that the test processes prohibits 689 // exit_group syscall using seccomp. Another observed scenario 690 // is that the test processes setups a userfaultfd for itself, 691 // then the main thread hangs when it wants to page in a page. 692 // Below we check if the test process still executes syscalls 693 // and kill it after ~1s of inactivity. 694 uint64 min_timeout_ms = program_timeout_ms * 3 / 5; 695 uint64 inactive_timeout_ms = syscall_timeout_ms * 20; 696 uint64 now = current_time_ms(); 697 uint32 now_executed = __atomic_load_n(output_data, __ATOMIC_RELAXED); 698 if (executed_calls != now_executed) { 699 executed_calls = now_executed; 700 last_executed = now; 701 } 702 // TODO: adjust timeout for progs with syz_usb_connect call. 703 if ((now - start < program_timeout_ms) && 704 (now - start < min_timeout_ms || now - last_executed < inactive_timeout_ms)) 705 continue; 706 #else 707 if (current_time_ms() - start < program_timeout_ms) 708 continue; 709 #endif 710 #else 711 if (current_time_ms() - start < /*{{{PROGRAM_TIMEOUT_MS}}}*/) 712 continue; 713 #endif 714 debug("killing hanging pid %d\n", pid); 715 kill_and_wait(pid, &status); 716 break; 717 } 718 #if SYZ_EXECUTOR 719 if (WEXITSTATUS(status) == kFailStatus) { 720 errno = 0; 721 fail("child failed"); 722 } 723 reply_execute(0); 724 #endif 725 #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR 726 remove_dir(cwdbuf); 727 #endif 728 #if SYZ_LEAK 729 // Note: this will fail under setuid sandbox because we don't have 730 // write permissions for the kmemleak file. 731 check_leaks(); 732 #endif 733 } 734 } 735 #else 736 static void loop(void) 737 { 738 execute_one(); 739 } 740 #endif 741 #endif 742 743 #if !SYZ_EXECUTOR 744 745 /*{{{RESULTS}}}*/ 746 747 #if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID 748 #if SYZ_THREADED 749 void execute_call(int call) 750 #elif SYZ_REPEAT 751 void execute_one(void) 752 #else 753 void loop(void) 754 #endif 755 { 756 /*{{{SYSCALLS}}}*/ 757 #if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT 758 close_fds(); 759 #endif 760 } 761 #endif 762 763 // This is the main function for csource. 764 int main(void) 765 { 766 /*{{{MMAP_DATA}}}*/ 767 768 #if SYZ_SYSCTL 769 setup_sysctl(); 770 #endif 771 #if SYZ_CGROUPS 772 setup_cgroups(); 773 #endif 774 #if SYZ_BINFMT_MISC 775 setup_binfmt_misc(); 776 #endif 777 #if SYZ_LEAK 778 setup_leak(); 779 #endif 780 #if SYZ_FAULT 781 setup_fault(); 782 #endif 783 #if SYZ_KCSAN 784 setup_kcsan(); 785 #endif 786 #if SYZ_USB 787 setup_usb(); 788 #endif 789 #if SYZ_802154 790 setup_802154(); 791 #endif 792 #if SYZ_SWAP 793 setup_swap(); 794 #endif 795 #if SYZ_HANDLE_SEGV 796 install_segv_handler(); 797 #endif 798 #if SYZ_HAVE_SETUP_EXT 799 setup_ext(); 800 #endif 801 #if SYZ_MULTI_PROC 802 for (procid = 0; procid < /*{{{PROCS}}}*/; procid++) { 803 if (fork() == 0) { 804 #endif 805 #if SYZ_USE_TMP_DIR || SYZ_SANDBOX_ANDROID 806 use_temporary_dir(); 807 #endif 808 /*{{{SANDBOX_FUNC}}}*/ 809 #if SYZ_HAVE_CLOSE_FDS && !SYZ_THREADED && !SYZ_REPEAT && !SYZ_SANDBOX_NONE && \ 810 !SYZ_SANDBOX_SETUID && !SYZ_SANDBOX_NAMESPACE && !SYZ_SANDBOX_ANDROID 811 close_fds(); 812 #endif 813 #if SYZ_MULTI_PROC 814 } 815 } 816 sleep(1000000); 817 #endif 818 #if !SYZ_MULTI_PROC && !SYZ_REPEAT && SYZ_LEAK 819 check_leaks(); 820 #endif 821 return 0; 822 } 823 #endif