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