• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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