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>
doexit(int status)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>
recover()58 static void recover()
59 {
60 _longjmp(segv_env, 1);
61 }
62 #endif
63
segv_handler(int sig,siginfo_t * info,void * ctx)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
install_segv_handler()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
kill_and_wait(int pid,int * status)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
sleep_ms(uint64 ms)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
current_time_ms()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
use_temporary_dir()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
remove_dir(const char * dir)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
inject_fault(int nth)212 static int inject_fault(int nth)
213 {
214 return 0;
215 }
216 #endif
217 #if SYZ_EXECUTOR
fault_injected(int fail_fd)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
thread_start(void * (* fn)(void *),void * arg)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
event_init(event_t * ev)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
event_reset(event_t * ev)264 static void event_reset(event_t* ev)
265 {
266 ev->state = 0;
267 }
268
event_set(event_t * ev)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
event_wait(event_t * ev)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
event_isset(event_t * ev)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
event_timedwait(event_t * ev,uint64 timeout)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
csum_inet_init(struct csum_inet * csum)340 static void csum_inet_init(struct csum_inet* csum)
341 {
342 csum->acc = 0;
343 }
344
csum_inet_update(struct csum_inet * csum,const uint8 * data,size_t length)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
csum_inet_digest(struct csum_inet * csum)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
thr(void * arg)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
execute_one()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
loop()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