1 /* SPDX-License-Identifier: MIT */
2 // autogenerated by syzkaller (https://github.com/google/syzkaller)
3
4 #include <dirent.h>
5 #include <endian.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <pthread.h>
9 #include <signal.h>
10 #include <stdarg.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/prctl.h>
17 #include <sys/stat.h>
18 #include <sys/syscall.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <sys/mman.h>
24
25 #include <linux/futex.h>
26
27 #include "liburing.h"
28 #include "helpers.h"
29 #include "../src/syscall.h"
30
31 #ifndef CONFIG_USE_SANITIZER
32 #if !defined(SYS_futex) && defined(SYS_futex_time64)
33 # define SYS_futex SYS_futex_time64
34 #endif
35
sleep_ms(uint64_t ms)36 static void sleep_ms(uint64_t ms)
37 {
38 usleep(ms * 1000);
39 }
40
current_time_ms(void)41 static uint64_t current_time_ms(void)
42 {
43 struct timespec ts;
44 if (clock_gettime(CLOCK_MONOTONIC, &ts))
45 exit(1);
46 return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
47 }
48
thread_start(void * (* fn)(void *),void * arg)49 static void thread_start(void* (*fn)(void*), void* arg)
50 {
51 pthread_t th;
52 pthread_attr_t attr;
53 pthread_attr_init(&attr);
54 pthread_attr_setstacksize(&attr, 128 << 10);
55 int i;
56 for (i = 0; i < 100; i++) {
57 if (pthread_create(&th, &attr, fn, arg) == 0) {
58 pthread_attr_destroy(&attr);
59 return;
60 }
61 if (errno == EAGAIN) {
62 usleep(50);
63 continue;
64 }
65 break;
66 }
67 exit(1);
68 }
69
70 typedef struct {
71 int state;
72 } event_t;
73
event_init(event_t * ev)74 static void event_init(event_t* ev)
75 {
76 ev->state = 0;
77 }
78
event_reset(event_t * ev)79 static void event_reset(event_t* ev)
80 {
81 ev->state = 0;
82 }
83
event_set(event_t * ev)84 static void event_set(event_t* ev)
85 {
86 if (ev->state)
87 exit(1);
88 __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
89 syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG);
90 }
91
event_wait(event_t * ev)92 static void event_wait(event_t* ev)
93 {
94 while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
95 syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
96 }
97
event_isset(event_t * ev)98 static int event_isset(event_t* ev)
99 {
100 return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
101 }
102
event_timedwait(event_t * ev,uint64_t timeout)103 static int event_timedwait(event_t* ev, uint64_t timeout)
104 {
105 uint64_t start = current_time_ms();
106 uint64_t now = start;
107 for (;;) {
108 uint64_t remain = timeout - (now - start);
109 struct timespec ts;
110 ts.tv_sec = remain / 1000;
111 ts.tv_nsec = (remain % 1000) * 1000 * 1000;
112 syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
113 if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED))
114 return 1;
115 now = current_time_ms();
116 if (now - start > timeout)
117 return 0;
118 }
119 }
120
write_file(const char * file,const char * what,...)121 static bool write_file(const char* file, const char* what, ...)
122 {
123 char buf[1024];
124 va_list args;
125 va_start(args, what);
126 vsnprintf(buf, sizeof(buf), what, args);
127 va_end(args);
128 buf[sizeof(buf) - 1] = 0;
129 int len = strlen(buf);
130 int fd = open(file, O_WRONLY | O_CLOEXEC);
131 if (fd == -1)
132 return false;
133 if (write(fd, buf, len) != len) {
134 int err = errno;
135 close(fd);
136 errno = err;
137 return false;
138 }
139 close(fd);
140 return true;
141 }
142
kill_and_wait(int pid,int * status)143 static void kill_and_wait(int pid, int* status)
144 {
145 kill(-pid, SIGKILL);
146 kill(pid, SIGKILL);
147 int i;
148 for (i = 0; i < 100; i++) {
149 if (waitpid(-1, status, WNOHANG | __WALL) == pid)
150 return;
151 usleep(1000);
152 }
153 DIR* dir = opendir("/sys/fs/fuse/connections");
154 if (dir) {
155 for (;;) {
156 struct dirent* ent = readdir(dir);
157 if (!ent)
158 break;
159 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
160 continue;
161 char abort[300];
162 snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
163 ent->d_name);
164 int fd = open(abort, O_WRONLY);
165 if (fd == -1) {
166 continue;
167 }
168 if (write(fd, abort, 1) < 0) {
169 }
170 close(fd);
171 }
172 closedir(dir);
173 } else {
174 }
175 while (waitpid(-1, status, __WALL) != pid) {
176 }
177 }
178
179 #define SYZ_HAVE_SETUP_TEST 1
setup_test(void)180 static void setup_test(void)
181 {
182 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
183 setpgrp();
184 write_file("/proc/self/oom_score_adj", "1000");
185 }
186
187 struct thread_t {
188 int created, call;
189 event_t ready, done;
190 };
191
192 static struct thread_t threads[16];
193 static void execute_call(int call);
194 static int running;
195
thr(void * arg)196 static void* thr(void* arg)
197 {
198 struct thread_t* th = (struct thread_t*)arg;
199 for (;;) {
200 event_wait(&th->ready);
201 event_reset(&th->ready);
202 execute_call(th->call);
203 __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
204 event_set(&th->done);
205 }
206 return 0;
207 }
208
execute_one(void)209 static void execute_one(void)
210 {
211 int i, call, thread;
212 for (call = 0; call < 3; call++) {
213 for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
214 thread++) {
215 struct thread_t* th = &threads[thread];
216 if (!th->created) {
217 th->created = 1;
218 event_init(&th->ready);
219 event_init(&th->done);
220 event_set(&th->done);
221 thread_start(thr, th);
222 }
223 if (!event_isset(&th->done))
224 continue;
225 event_reset(&th->done);
226 th->call = call;
227 __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
228 event_set(&th->ready);
229 event_timedwait(&th->done, 45);
230 break;
231 }
232 }
233 for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
234 sleep_ms(1);
235 }
236
237 static void execute_one(void);
238
239 #define WAIT_FLAGS __WALL
240
loop(void)241 static void loop(void)
242 {
243 for (;;) {
244 int pid = fork();
245 if (pid < 0)
246 exit(1);
247 if (pid == 0) {
248 setup_test();
249 execute_one();
250 exit(0);
251 }
252 int status = 0;
253 uint64_t start = current_time_ms();
254 for (;;) {
255 if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
256 break;
257 sleep_ms(1);
258 if (current_time_ms() - start < 5 * 1000)
259 continue;
260 kill_and_wait(pid, &status);
261 break;
262 }
263 }
264 }
265
266 static uint64_t r[1] = {0xffffffffffffffff};
267
execute_call(int call)268 void execute_call(int call)
269 {
270 long res;
271 switch (call) {
272 case 0:
273 *(uint32_t*)0x20000040 = 0;
274 *(uint32_t*)0x20000044 = 0;
275 *(uint32_t*)0x20000048 = 0;
276 *(uint32_t*)0x2000004c = 0;
277 *(uint32_t*)0x20000050 = 0;
278 *(uint32_t*)0x20000054 = 0;
279 *(uint32_t*)0x20000058 = 0;
280 *(uint32_t*)0x2000005c = 0;
281 *(uint32_t*)0x20000060 = 0;
282 *(uint32_t*)0x20000064 = 0;
283 *(uint32_t*)0x20000068 = 0;
284 *(uint32_t*)0x2000006c = 0;
285 *(uint32_t*)0x20000070 = 0;
286 *(uint32_t*)0x20000074 = 0;
287 *(uint32_t*)0x20000078 = 0;
288 *(uint32_t*)0x2000007c = 0;
289 *(uint32_t*)0x20000080 = 0;
290 *(uint32_t*)0x20000084 = 0;
291 *(uint64_t*)0x20000088 = 0;
292 *(uint32_t*)0x20000090 = 0;
293 *(uint32_t*)0x20000094 = 0;
294 *(uint32_t*)0x20000098 = 0;
295 *(uint32_t*)0x2000009c = 0;
296 *(uint32_t*)0x200000a0 = 0;
297 *(uint32_t*)0x200000a4 = 0;
298 *(uint32_t*)0x200000a8 = 0;
299 *(uint32_t*)0x200000ac = 0;
300 *(uint64_t*)0x200000b0 = 0;
301 res = __sys_io_uring_setup(0x64, (struct io_uring_params *) 0x20000040UL);
302 if (res != -1)
303 r[0] = res;
304 break;
305 case 1:
306 __sys_io_uring_register((long)r[0], 0, 0, 0);
307 break;
308 case 2:
309 __sys_io_uring_register((long)r[0], 0, 0, 0);
310 break;
311 }
312 }
313
sig_int(int sig)314 static void sig_int(int sig)
315 {
316 exit(0);
317 }
318
main(int argc,char * argv[])319 int main(int argc, char *argv[])
320 {
321 if (argc > 1)
322 return T_EXIT_SKIP;
323 signal(SIGINT, sig_int);
324 mmap((void *) 0x20000000, 0x1000000, 3, MAP_ANON|MAP_PRIVATE, -1, 0);
325 signal(SIGALRM, sig_int);
326 alarm(5);
327
328 loop();
329 return T_EXIT_PASS;
330 }
331 #else
main(int argc,char * argv[])332 int main(int argc, char *argv[])
333 {
334 return T_EXIT_SKIP;
335 }
336 #endif
337