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/failf/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 #include <endian.h> // for htobe*. 19 #include <stdint.h> 20 #include <stdio.h> // for fmt arguments 21 #include <stdlib.h> 22 #include <string.h> 23 24 #if SYZ_TRACE 25 #include <errno.h> 26 #endif 27 28 #if SYZ_EXECUTOR && !GOOS_linux 29 #include <unistd.h> 30 NORETURN void doexit(int status) 31 { 32 _exit(status); 33 for (;;) { 34 } 35 } 36 #endif 37 38 #if SYZ_EXECUTOR || SYZ_PROCS || SYZ_REPEAT && SYZ_ENABLE_CGROUPS || \ 39 __NR_syz_mount_image || __NR_syz_read_part_table 40 unsigned long long procid; 41 #endif 42 43 #if !GOOS_fuchsia && !GOOS_windows 44 #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV 45 #include <setjmp.h> 46 #include <signal.h> 47 #include <string.h> 48 49 #if GOOS_linux 50 #include <sys/syscall.h> 51 #endif 52 53 static __thread int skip_segv; 54 static __thread jmp_buf segv_env; 55 56 #if GOOS_akaros 57 #include <parlib/parlib.h> 58 static void recover() 59 { 60 _longjmp(segv_env, 1); 61 } 62 #endif 63 64 static void segv_handler(int sig, siginfo_t* info, void* ctx) 65 { 66 // Generated programs can contain bad (unmapped/protected) addresses, 67 // which cause SIGSEGVs during copyin/copyout. 68 // This handler ignores such crashes to allow the program to proceed. 69 // We additionally opportunistically check that the faulty address 70 // is not within executable data region, because such accesses can corrupt 71 // output region and then fuzzer will fail on corrupted data. 72 uintptr_t addr = (uintptr_t)info->si_addr; 73 const uintptr_t prog_start = 1 << 20; 74 const uintptr_t prog_end = 100 << 20; 75 if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { 76 debug("SIGSEGV on %p, skipping\n", (void*)addr); 77 #if GOOS_akaros 78 struct user_context* uctx = (struct user_context*)ctx; 79 uctx->tf.hw_tf.tf_rip = (long)(void*)recover; 80 return; 81 #else 82 _longjmp(segv_env, 1); 83 #endif 84 } 85 debug("SIGSEGV on %p, exiting\n", (void*)addr); 86 doexit(sig); 87 } 88 89 static void install_segv_handler() 90 { 91 struct sigaction sa; 92 #if GOOS_linux 93 // Don't need that SIGCANCEL/SIGSETXID glibc stuff. 94 // SIGCANCEL sent to main thread causes it to exit 95 // without bringing down the whole group. 96 memset(&sa, 0, sizeof(sa)); 97 sa.sa_handler = SIG_IGN; 98 syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); 99 syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); 100 #endif 101 memset(&sa, 0, sizeof(sa)); 102 sa.sa_sigaction = segv_handler; 103 sa.sa_flags = SA_NODEFER | SA_SIGINFO; 104 sigaction(SIGSEGV, &sa, NULL); 105 sigaction(SIGBUS, &sa, NULL); 106 } 107 108 #define NONFAILING(...) \ 109 { \ 110 __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ 111 if (_setjmp(segv_env) == 0) { \ 112 __VA_ARGS__; \ 113 } \ 114 __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ 115 } 116 #endif 117 #endif 118 119 #if !GOOS_linux 120 #if (SYZ_EXECUTOR || SYZ_REPEAT) && SYZ_EXECUTOR_USES_FORK_SERVER 121 #include <signal.h> 122 #include <sys/types.h> 123 #include <sys/wait.h> 124 125 static void kill_and_wait(int pid, int* status) 126 { 127 kill(pid, SIGKILL); 128 while (waitpid(-1, status, 0) != pid) { 129 } 130 } 131 #endif 132 #endif 133 134 #if !GOOS_windows 135 #if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER 136 static void sleep_ms(uint64 ms) 137 { 138 usleep(ms * 1000); 139 } 140 #endif 141 142 #if SYZ_EXECUTOR || SYZ_THREADED || SYZ_REPEAT && SYZ_EXECUTOR_USES_FORK_SERVER 143 #include <time.h> 144 145 static uint64 current_time_ms() 146 { 147 struct timespec ts; 148 if (clock_gettime(CLOCK_MONOTONIC, &ts)) 149 fail("clock_gettime failed"); 150 return (uint64)ts.tv_sec * 1000 + (uint64)ts.tv_nsec / 1000000; 151 } 152 #endif 153 154 #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR 155 #include <stdlib.h> 156 #include <sys/stat.h> 157 #include <unistd.h> 158 159 static void use_temporary_dir() 160 { 161 char tmpdir_template[] = "./syzkaller.XXXXXX"; 162 char* tmpdir = mkdtemp(tmpdir_template); 163 if (!tmpdir) 164 fail("failed to mkdtemp"); 165 if (chmod(tmpdir, 0777)) 166 fail("failed to chmod"); 167 if (chdir(tmpdir)) 168 fail("failed to chdir"); 169 } 170 #endif 171 #endif 172 173 #if GOOS_akaros || GOOS_netbsd || GOOS_freebsd || GOOS_test 174 #if SYZ_EXECUTOR || SYZ_EXECUTOR_USES_FORK_SERVER && SYZ_REPEAT && SYZ_USE_TMP_DIR 175 #include <dirent.h> 176 #include <stdio.h> 177 #include <string.h> 178 #include <sys/stat.h> 179 #include <sys/types.h> 180 181 static void remove_dir(const char* dir) 182 { 183 DIR* dp; 184 struct dirent* ep; 185 dp = opendir(dir); 186 if (dp == NULL) 187 exitf("opendir(%s) failed", dir); 188 while ((ep = readdir(dp))) { 189 if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) 190 continue; 191 char filename[FILENAME_MAX]; 192 snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name); 193 struct stat st; 194 if (lstat(filename, &st)) 195 exitf("lstat(%s) failed", filename); 196 if (S_ISDIR(st.st_mode)) { 197 remove_dir(filename); 198 continue; 199 } 200 if (unlink(filename)) 201 exitf("unlink(%s) failed", filename); 202 } 203 closedir(dp); 204 if (rmdir(dir)) 205 exitf("rmdir(%s) failed", dir); 206 } 207 #endif 208 #endif 209 210 #if !GOOS_linux 211 #if SYZ_EXECUTOR || SYZ_FAULT_INJECTION 212 static int inject_fault(int nth) 213 { 214 return 0; 215 } 216 #endif 217 #if SYZ_EXECUTOR 218 static int fault_injected(int fail_fd) 219 { 220 return 0; 221 } 222 #endif 223 #endif 224 225 #if !GOOS_windows 226 #if SYZ_EXECUTOR || SYZ_THREADED 227 #include <pthread.h> 228 229 static void thread_start(void* (*fn)(void*), void* arg) 230 { 231 pthread_t th; 232 pthread_attr_t attr; 233 pthread_attr_init(&attr); 234 pthread_attr_setstacksize(&attr, 128 << 10); 235 if (pthread_create(&th, &attr, fn, arg)) 236 exitf("pthread_create failed"); 237 pthread_attr_destroy(&attr); 238 } 239 240 #endif 241 #endif 242 243 #if GOOS_freebsd || GOOS_netbsd || GOOS_akaros || GOOS_test 244 #if SYZ_EXECUTOR || SYZ_THREADED 245 246 #include <pthread.h> 247 #include <time.h> 248 249 typedef struct { 250 pthread_mutex_t mu; 251 pthread_cond_t cv; 252 int state; 253 } event_t; 254 255 static void event_init(event_t* ev) 256 { 257 if (pthread_mutex_init(&ev->mu, 0)) 258 fail("pthread_mutex_init failed"); 259 if (pthread_cond_init(&ev->cv, 0)) 260 fail("pthread_cond_init failed"); 261 ev->state = 0; 262 } 263 264 static void event_reset(event_t* ev) 265 { 266 ev->state = 0; 267 } 268 269 static void event_set(event_t* ev) 270 { 271 pthread_mutex_lock(&ev->mu); 272 if (ev->state) 273 fail("event already set"); 274 ev->state = 1; 275 pthread_mutex_unlock(&ev->mu); 276 pthread_cond_broadcast(&ev->cv); 277 } 278 279 static void event_wait(event_t* ev) 280 { 281 pthread_mutex_lock(&ev->mu); 282 while (!ev->state) 283 pthread_cond_wait(&ev->cv, &ev->mu); 284 pthread_mutex_unlock(&ev->mu); 285 } 286 287 static int event_isset(event_t* ev) 288 { 289 pthread_mutex_lock(&ev->mu); 290 int res = ev->state; 291 pthread_mutex_unlock(&ev->mu); 292 return res; 293 } 294 295 static int event_timedwait(event_t* ev, uint64 timeout) 296 { 297 uint64 start = current_time_ms(); 298 uint64 now = start; 299 pthread_mutex_lock(&ev->mu); 300 for (;;) { 301 if (ev->state) 302 break; 303 uint64 remain = timeout - (now - start); 304 struct timespec ts; 305 ts.tv_sec = remain / 1000; 306 ts.tv_nsec = (remain % 1000) * 1000 * 1000; 307 pthread_cond_timedwait(&ev->cv, &ev->mu, &ts); 308 now = current_time_ms(); 309 if (now - start > timeout) 310 break; 311 } 312 int res = ev->state; 313 pthread_mutex_unlock(&ev->mu); 314 return res; 315 } 316 #endif 317 #endif 318 319 #if SYZ_EXECUTOR || SYZ_USE_BITMASKS 320 #define BITMASK_LEN(type, bf_len) (type)((1ull << (bf_len)) - 1) 321 322 #define BITMASK_LEN_OFF(type, bf_off, bf_len) (type)(BITMASK_LEN(type, (bf_len)) << (bf_off)) 323 324 #define STORE_BY_BITMASK(type, addr, val, bf_off, bf_len) \ 325 if ((bf_off) == 0 && (bf_len) == 0) { \ 326 *(type*)(addr) = (type)(val); \ 327 } else { \ 328 type new_val = *(type*)(addr); \ 329 new_val &= ~BITMASK_LEN_OFF(type, (bf_off), (bf_len)); \ 330 new_val |= ((type)(val)&BITMASK_LEN(type, (bf_len))) << (bf_off); \ 331 *(type*)(addr) = new_val; \ 332 } 333 #endif 334 335 #if SYZ_EXECUTOR || SYZ_USE_CHECKSUMS 336 struct csum_inet { 337 uint32 acc; 338 }; 339 340 static void csum_inet_init(struct csum_inet* csum) 341 { 342 csum->acc = 0; 343 } 344 345 static void csum_inet_update(struct csum_inet* csum, const uint8* data, size_t length) 346 { 347 if (length == 0) 348 return; 349 350 size_t i; 351 for (i = 0; i < length - 1; i += 2) 352 csum->acc += *(uint16*)&data[i]; 353 354 if (length & 1) 355 csum->acc += (uint16)data[length - 1]; 356 357 while (csum->acc > 0xffff) 358 csum->acc = (csum->acc & 0xffff) + (csum->acc >> 16); 359 } 360 361 static uint16 csum_inet_digest(struct csum_inet* csum) 362 { 363 return ~csum->acc; 364 } 365 #endif 366 367 #if GOOS_akaros 368 #include "common_akaros.h" 369 #elif GOOS_freebsd || GOOS_netbsd 370 #include "common_bsd.h" 371 #elif GOOS_fuchsia 372 #include "common_fuchsia.h" 373 #elif GOOS_linux 374 #include "common_linux.h" 375 #elif GOOS_test 376 #include "common_test.h" 377 #elif GOOS_windows 378 #include "common_windows.h" 379 #elif GOOS_test 380 #include "common_test.h" 381 #else 382 #error "unknown OS" 383 #endif 384 385 #if SYZ_THREADED 386 struct thread_t { 387 int created, call; 388 event_t ready, done; 389 }; 390 391 static struct thread_t threads[16]; 392 static void execute_call(int call); 393 static int running; 394 395 static void* thr(void* arg) 396 { 397 struct thread_t* th = (struct thread_t*)arg; 398 for (;;) { 399 event_wait(&th->ready); 400 event_reset(&th->ready); 401 execute_call(th->call); 402 __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); 403 event_set(&th->done); 404 } 405 return 0; 406 } 407 408 #if SYZ_REPEAT 409 static void execute_one() 410 #else 411 static void loop() 412 #endif 413 { 414 #if SYZ_REPRO 415 if (write(1, "executing program\n", sizeof("executing program\n") - 1)) { 416 } 417 #endif 418 #if SYZ_TRACE 419 printf("### start\n"); 420 #endif 421 int i, call, thread; 422 #if SYZ_COLLIDE 423 int collide = 0; 424 again: 425 #endif 426 for (call = 0; call < [[NUM_CALLS]]; call++) { 427 for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) { 428 struct thread_t* th = &threads[thread]; 429 if (!th->created) { 430 th->created = 1; 431 event_init(&th->ready); 432 event_init(&th->done); 433 event_set(&th->done); 434 thread_start(thr, th); 435 } 436 if (!event_isset(&th->done)) 437 continue; 438 event_reset(&th->done); 439 th->call = call; 440 __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); 441 event_set(&th->ready); 442 #if SYZ_COLLIDE 443 if (collide && (call % 2) == 0) 444 break; 445 #endif 446 event_timedwait(&th->done, 45); 447 break; 448 } 449 } 450 for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) 451 sleep_ms(1); 452 #if SYZ_COLLIDE 453 if (!collide) { 454 collide = 1; 455 goto again; 456 } 457 #endif 458 } 459 #endif 460 461 #if SYZ_EXECUTOR || SYZ_REPEAT 462 static void execute_one(); 463 #if SYZ_EXECUTOR_USES_FORK_SERVER 464 #include <signal.h> 465 #include <sys/types.h> 466 #include <sys/wait.h> 467 468 #if GOOS_linux 469 #define WAIT_FLAGS __WALL 470 #else 471 #define WAIT_FLAGS 0 472 #endif 473 474 #if SYZ_EXECUTOR 475 static void reply_handshake(); 476 #endif 477 478 static void loop() 479 { 480 #if SYZ_HAVE_SETUP_LOOP 481 setup_loop(); 482 #endif 483 #if SYZ_EXECUTOR 484 // Tell parent that we are ready to serve. 485 reply_handshake(); 486 #endif 487 #if SYZ_EXECUTOR && GOOS_akaros 488 // For akaros we do exec in the child process because new threads can't be created in the fork child. 489 // Thus we proxy input program over the child_pipe to the child process. 490 int child_pipe[2]; 491 if (pipe(child_pipe)) 492 fail("pipe failed"); 493 #endif 494 int iter; 495 #if SYZ_REPEAT_TIMES 496 for (iter = 0; iter < [[REPEAT_TIMES]]; iter++) { 497 #else 498 for (iter = 0;; iter++) { 499 #endif 500 #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR 501 // Create a new private work dir for this test (removed at the end of the loop). 502 char cwdbuf[32]; 503 sprintf(cwdbuf, "./%d", iter); 504 if (mkdir(cwdbuf, 0777)) 505 fail("failed to mkdir"); 506 #endif 507 #if SYZ_HAVE_RESET_LOOP 508 reset_loop(); 509 #endif 510 #if SYZ_EXECUTOR 511 receive_execute(); 512 #endif 513 int pid = fork(); 514 if (pid < 0) 515 fail("clone failed"); 516 if (pid == 0) { 517 #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR 518 if (chdir(cwdbuf)) 519 fail("failed to chdir"); 520 #endif 521 #if SYZ_HAVE_SETUP_TEST 522 setup_test(); 523 #endif 524 #if GOOS_akaros 525 #if SYZ_EXECUTOR 526 dup2(child_pipe[0], kInPipeFd); 527 close(child_pipe[0]); 528 close(child_pipe[1]); 529 #endif 530 execl(program_name, program_name, "child", NULL); 531 fail("execl failed"); 532 #else 533 #if SYZ_EXECUTOR 534 close(kInPipeFd); 535 #endif 536 #if SYZ_EXECUTOR && SYZ_EXECUTOR_USES_SHMEM 537 close(kOutPipeFd); 538 #endif 539 execute_one(); 540 debug("worker exiting\n"); 541 #if SYZ_HAVE_RESET_TEST 542 reset_test(); 543 #endif 544 doexit(0); 545 #endif 546 } 547 debug("spawned worker pid %d\n", pid); 548 549 #if SYZ_EXECUTOR && GOOS_akaros 550 resend_execute(child_pipe[1]); 551 #endif 552 // We used to use sigtimedwait(SIGCHLD) to wait for the subprocess. 553 // But SIGCHLD is also delivered when a process stops/continues, 554 // so it would require a loop with status analysis and timeout recalculation. 555 // SIGCHLD should also unblock the usleep below, so the spin loop 556 // should be as efficient as sigtimedwait. 557 int status = 0; 558 uint64 start = current_time_ms(); 559 #if SYZ_EXECUTOR && SYZ_EXECUTOR_USES_SHMEM 560 uint64 last_executed = start; 561 uint32 executed_calls = __atomic_load_n(output_data, __ATOMIC_RELAXED); 562 #endif 563 for (;;) { 564 if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) 565 break; 566 sleep_ms(1); 567 #if SYZ_EXECUTOR && SYZ_EXECUTOR_USES_SHMEM 568 // Even though the test process executes exit at the end 569 // and execution time of each syscall is bounded by 20ms, 570 // this backup watchdog is necessary and its performance is important. 571 // The problem is that exit in the test processes can fail (sic). 572 // One observed scenario is that the test processes prohibits 573 // exit_group syscall using seccomp. Another observed scenario 574 // is that the test processes setups a userfaultfd for itself, 575 // then the main thread hangs when it wants to page in a page. 576 // Below we check if the test process still executes syscalls 577 // and kill it after 1s of inactivity. 578 uint64 now = current_time_ms(); 579 uint32 now_executed = __atomic_load_n(output_data, __ATOMIC_RELAXED); 580 if (executed_calls != now_executed) { 581 executed_calls = now_executed; 582 last_executed = now; 583 } 584 if ((now - start < 5 * 1000) && (now - start < 3 * 1000 || now - last_executed < 1000)) 585 continue; 586 #else 587 if (current_time_ms() - start < 5 * 1000) 588 continue; 589 #endif 590 debug("killing\n"); 591 kill_and_wait(pid, &status); 592 break; 593 } 594 #if SYZ_EXECUTOR 595 status = WEXITSTATUS(status); 596 if (status == kFailStatus) 597 fail("child failed"); 598 if (status == kErrorStatus) 599 error("child errored"); 600 reply_execute(0); 601 #endif 602 #if SYZ_EXECUTOR || SYZ_USE_TMP_DIR 603 remove_dir(cwdbuf); 604 #endif 605 } 606 } 607 #else 608 static void loop() 609 { 610 execute_one(); 611 } 612 #endif 613 #endif 614 615 // clang-format off 616 // clang-format badly mishandles this part, moreover different versions mishandle it differently. 617 #if !SYZ_EXECUTOR 618 [[SYSCALL_DEFINES]] 619 620 [[RESULTS]] 621 622 #if SYZ_THREADED || SYZ_REPEAT || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE 623 #if SYZ_THREADED 624 void execute_call(int call) 625 #elif SYZ_REPEAT 626 void execute_one() 627 #else 628 void loop() 629 #endif 630 { 631 [[SYSCALLS]] 632 } 633 #endif 634 635 // This is the main function for csource. 636 #if GOOS_akaros && SYZ_REPEAT 637 #include <string.h> 638 639 int main(int argc, char** argv) 640 { 641 [[MMAP_DATA]] 642 643 program_name = argv[0]; 644 if (argc == 2 && strcmp(argv[1], "child") == 0) 645 child(); 646 #else 647 int main() 648 { 649 [[MMAP_DATA]] 650 #endif 651 // clang-format on 652 653 #if SYZ_HANDLE_SEGV 654 install_segv_handler(); 655 #endif 656 #if SYZ_PROCS 657 for (procid = 0; procid < [[PROCS]]; procid++) { 658 if (fork() == 0) { 659 #endif 660 #if SYZ_USE_TMP_DIR 661 use_temporary_dir(); 662 #endif 663 [[SANDBOX_FUNC]] 664 #if SYZ_PROCS 665 } 666 } 667 sleep(1000000); 668 #endif 669 return 0; 670 } 671 #endif 672