• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 
6 #include <ddk/driver.h>
7 #include <fcntl.h>
8 #include <lib/fdio/util.h>
9 #include <poll.h>
10 #include <signal.h>
11 #include <stdlib.h>
12 #include <sys/file.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <sys/uio.h>
19 #include <time.h>
20 #include <unistd.h>
21 #include <utime.h>
22 #include <zircon/process.h>
23 #include <zircon/syscalls.h>
24 
25 #if SYZ_EXECUTOR || SYZ_HANDLE_SEGV
26 #include <pthread.h>
27 #include <setjmp.h>
28 #include <zircon/syscalls/debug.h>
29 #include <zircon/syscalls/exception.h>
30 #include <zircon/syscalls/object.h>
31 #include <zircon/syscalls/port.h>
32 
33 static __thread int skip_segv;
34 static __thread jmp_buf segv_env;
35 
segv_handler()36 static void segv_handler()
37 {
38 	if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED)) {
39 		debug("recover: skipping\n");
40 		longjmp(segv_env, 1);
41 	}
42 	debug("recover: exiting\n");
43 	doexit(SIGSEGV);
44 }
45 
ex_handler(void * arg)46 static void* ex_handler(void* arg)
47 {
48 	zx_handle_t port = (zx_handle_t)(long)arg;
49 	for (int i = 0; i < 10000; i++) {
50 		zx_port_packet_t packet = {};
51 		zx_status_t status = zx_port_wait(port, ZX_TIME_INFINITE, &packet);
52 		if (status != ZX_OK) {
53 			debug("zx_port_wait failed: %d\n", status);
54 			continue;
55 		}
56 		debug("got exception packet: type=%d status=%d tid=%llu\n",
57 		      packet.type, packet.status, (unsigned long long)(packet.exception.tid));
58 		zx_handle_t thread;
59 		status = zx_object_get_child(zx_process_self(), packet.exception.tid,
60 					     ZX_RIGHT_SAME_RIGHTS, &thread);
61 		if (status != ZX_OK) {
62 			debug("zx_object_get_child failed: %d\n", status);
63 			continue;
64 		}
65 		zx_thread_state_general_regs_t regs;
66 		status = zx_thread_read_state(thread, ZX_THREAD_STATE_GENERAL_REGS,
67 					      &regs, sizeof(regs));
68 		if (status != ZX_OK) {
69 			debug("zx_thread_read_state failed: %d (%d)\n",
70 			      (int)sizeof(regs), status);
71 		} else {
72 #if GOARCH_amd64
73 			regs.rip = (uint64)(void*)&segv_handler;
74 #elif GOARCH_arm64
75 			regs.pc = (uint64)(void*)&segv_handler;
76 #else
77 #error "unsupported arch"
78 #endif
79 			status = zx_thread_write_state(thread, ZX_THREAD_STATE_GENERAL_REGS, &regs, sizeof(regs));
80 			if (status != ZX_OK) {
81 				debug("zx_thread_write_state failed: %d\n", status);
82 			}
83 		}
84 		status = zx_task_resume(thread, ZX_RESUME_EXCEPTION);
85 		if (status != ZX_OK) {
86 			debug("zx_task_resume failed: %d\n", status);
87 		}
88 		zx_handle_close(thread);
89 	}
90 	doexit(1);
91 	return 0;
92 }
93 
install_segv_handler()94 static void install_segv_handler()
95 {
96 	zx_status_t status;
97 	zx_handle_t port;
98 	if ((status = zx_port_create(0, &port)) != ZX_OK)
99 		fail("zx_port_create failed: %d", status);
100 	if ((status = zx_task_bind_exception_port(zx_process_self(), port, 0, 0)) != ZX_OK)
101 		fail("zx_task_bind_exception_port failed: %d", status);
102 	pthread_t th;
103 	if (pthread_create(&th, 0, ex_handler, (void*)(long)port))
104 		fail("pthread_create failed");
105 }
106 
107 #define NONFAILING(...)                                              \
108 	{                                                            \
109 		__atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \
110 		if (sigsetjmp(segv_env, 0) == 0) {                   \
111 			__VA_ARGS__;                                 \
112 		}                                                    \
113 		__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
114 	}
115 #endif
116 
117 #if SYZ_EXECUTOR || SYZ_THREADED
118 #include <unistd.h>
119 
120 // Fuchsia's pthread_cond_timedwait just returns immidiately, so we use simple spin wait.
121 typedef struct {
122 	int state;
123 } event_t;
124 
event_init(event_t * ev)125 static void event_init(event_t* ev)
126 {
127 	ev->state = 0;
128 }
129 
event_reset(event_t * ev)130 static void event_reset(event_t* ev)
131 {
132 	ev->state = 0;
133 }
134 
event_set(event_t * ev)135 static void event_set(event_t* ev)
136 {
137 	if (ev->state)
138 		fail("event already set");
139 	__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
140 }
141 
event_wait(event_t * ev)142 static void event_wait(event_t* ev)
143 {
144 	while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
145 		usleep(200);
146 }
147 
event_isset(event_t * ev)148 static int event_isset(event_t* ev)
149 {
150 	return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
151 }
152 
event_timedwait(event_t * ev,uint64 timeout_ms)153 static int event_timedwait(event_t* ev, uint64 timeout_ms)
154 {
155 	uint64 start = current_time_ms();
156 	for (;;) {
157 		if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
158 			return 1;
159 		if (current_time_ms() - start > timeout_ms)
160 			return 0;
161 		usleep(200);
162 	}
163 }
164 #endif
165 
166 #if SYZ_EXECUTOR || __NR_syz_mmap
syz_mmap(size_t addr,size_t size)167 long syz_mmap(size_t addr, size_t size)
168 {
169 	zx_handle_t root = zx_vmar_root_self();
170 	zx_info_vmar_t info;
171 	zx_status_t status = zx_object_get_info(root, ZX_INFO_VMAR, &info, sizeof(info), 0, 0);
172 	if (status != ZX_OK)
173 		fail("zx_object_get_info(ZX_INFO_VMAR) failed: %d", status);
174 	zx_handle_t vmo;
175 	status = zx_vmo_create(size, 0, &vmo);
176 	if (status != ZX_OK)
177 		return status;
178 	uintptr_t mapped_addr;
179 	status = zx_vmar_map(root, addr - info.base, vmo, 0, size,
180 			     ZX_VM_FLAG_SPECIFIC_OVERWRITE | ZX_VM_FLAG_PERM_READ |
181 				 ZX_VM_FLAG_PERM_WRITE | ZX_VM_FLAG_PERM_EXECUTE,
182 			     &mapped_addr);
183 	return status;
184 }
185 #endif
186 
187 #if SYZ_EXECUTOR || __NR_syz_process_self
syz_process_self()188 static long syz_process_self()
189 {
190 	return zx_process_self();
191 }
192 #endif
193 
194 #if SYZ_EXECUTOR || __NR_syz_thread_self
syz_thread_self()195 static long syz_thread_self()
196 {
197 	return zx_thread_self();
198 }
199 #endif
200 
201 #if SYZ_EXECUTOR || __NR_syz_vmar_root_self
syz_vmar_root_self()202 static long syz_vmar_root_self()
203 {
204 	return zx_vmar_root_self();
205 }
206 #endif
207 
208 #if SYZ_EXECUTOR || __NR_syz_job_default
syz_job_default()209 static long syz_job_default()
210 {
211 	return zx_job_default();
212 }
213 #endif
214 
215 #if SYZ_EXECUTOR || __NR_syz_future_time
syz_future_time(long when)216 static long syz_future_time(long when)
217 {
218 	zx_time_t delta_ms;
219 	switch (when) {
220 	case 0:
221 		delta_ms = 5;
222 	case 1:
223 		delta_ms = 30;
224 	default:
225 		delta_ms = 10000;
226 	}
227 	zx_time_t now = zx_clock_get(ZX_CLOCK_MONOTONIC);
228 	return now + delta_ms * 1000 * 1000;
229 }
230 #endif
231 
232 #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE
233 static void loop();
do_sandbox_none(void)234 static int do_sandbox_none(void)
235 {
236 	loop();
237 	return 0;
238 }
239 #endif
240 
241 #if SYZ_EXECUTOR
242 #define do_sandbox_setuid() 0
243 #define do_sandbox_namespace() 0
244 #endif
245