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