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