Jens Axboe | e502435 | 2020-02-11 20:34:12 -0700 | [diff] [blame] | 1 | /* SPDX-License-Identifier: MIT */ |
Jens Axboe | 78f59df | 2019-04-23 12:05:18 -0600 | [diff] [blame] | 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> |
Jens Axboe | 459e895 | 2020-04-24 07:39:24 -0600 | [diff] [blame^] | 23 | #include <sys/mman.h> |
Jens Axboe | 78f59df | 2019-04-23 12:05:18 -0600 | [diff] [blame] | 24 | |
| 25 | #include <linux/futex.h> |
| 26 | |
| 27 | static void sleep_ms(uint64_t ms) |
| 28 | { |
| 29 | usleep(ms * 1000); |
| 30 | } |
| 31 | |
| 32 | static uint64_t current_time_ms(void) |
| 33 | { |
| 34 | struct timespec ts; |
| 35 | if (clock_gettime(CLOCK_MONOTONIC, &ts)) |
| 36 | exit(1); |
| 37 | return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; |
| 38 | } |
| 39 | |
| 40 | static void thread_start(void* (*fn)(void*), void* arg) |
| 41 | { |
| 42 | pthread_t th; |
| 43 | pthread_attr_t attr; |
| 44 | pthread_attr_init(&attr); |
| 45 | pthread_attr_setstacksize(&attr, 128 << 10); |
| 46 | int i; |
| 47 | for (i = 0; i < 100; i++) { |
| 48 | if (pthread_create(&th, &attr, fn, arg) == 0) { |
| 49 | pthread_attr_destroy(&attr); |
| 50 | return; |
| 51 | } |
| 52 | if (errno == EAGAIN) { |
| 53 | usleep(50); |
| 54 | continue; |
| 55 | } |
| 56 | break; |
| 57 | } |
| 58 | exit(1); |
| 59 | } |
| 60 | |
| 61 | typedef struct { |
| 62 | int state; |
| 63 | } event_t; |
| 64 | |
| 65 | static void event_init(event_t* ev) |
| 66 | { |
| 67 | ev->state = 0; |
| 68 | } |
| 69 | |
| 70 | static void event_reset(event_t* ev) |
| 71 | { |
| 72 | ev->state = 0; |
| 73 | } |
| 74 | |
| 75 | static void event_set(event_t* ev) |
| 76 | { |
| 77 | if (ev->state) |
| 78 | exit(1); |
| 79 | __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); |
| 80 | syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG); |
| 81 | } |
| 82 | |
| 83 | static void event_wait(event_t* ev) |
| 84 | { |
| 85 | while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) |
| 86 | syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0); |
| 87 | } |
| 88 | |
| 89 | static int event_isset(event_t* ev) |
| 90 | { |
| 91 | return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); |
| 92 | } |
| 93 | |
| 94 | static int event_timedwait(event_t* ev, uint64_t timeout) |
| 95 | { |
| 96 | uint64_t start = current_time_ms(); |
| 97 | uint64_t now = start; |
| 98 | for (;;) { |
| 99 | uint64_t remain = timeout - (now - start); |
| 100 | struct timespec ts; |
| 101 | ts.tv_sec = remain / 1000; |
| 102 | ts.tv_nsec = (remain % 1000) * 1000 * 1000; |
| 103 | syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts); |
| 104 | if (__atomic_load_n(&ev->state, __ATOMIC_RELAXED)) |
| 105 | return 1; |
| 106 | now = current_time_ms(); |
| 107 | if (now - start > timeout) |
| 108 | return 0; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | static bool write_file(const char* file, const char* what, ...) |
| 113 | { |
| 114 | char buf[1024]; |
| 115 | va_list args; |
| 116 | va_start(args, what); |
| 117 | vsnprintf(buf, sizeof(buf), what, args); |
| 118 | va_end(args); |
| 119 | buf[sizeof(buf) - 1] = 0; |
| 120 | int len = strlen(buf); |
| 121 | int fd = open(file, O_WRONLY | O_CLOEXEC); |
| 122 | if (fd == -1) |
| 123 | return false; |
| 124 | if (write(fd, buf, len) != len) { |
| 125 | int err = errno; |
| 126 | close(fd); |
| 127 | errno = err; |
| 128 | return false; |
| 129 | } |
| 130 | close(fd); |
| 131 | return true; |
| 132 | } |
| 133 | |
| 134 | static void kill_and_wait(int pid, int* status) |
| 135 | { |
| 136 | kill(-pid, SIGKILL); |
| 137 | kill(pid, SIGKILL); |
| 138 | int i; |
| 139 | for (i = 0; i < 100; i++) { |
| 140 | if (waitpid(-1, status, WNOHANG | __WALL) == pid) |
| 141 | return; |
| 142 | usleep(1000); |
| 143 | } |
| 144 | DIR* dir = opendir("/sys/fs/fuse/connections"); |
| 145 | if (dir) { |
| 146 | for (;;) { |
| 147 | struct dirent* ent = readdir(dir); |
| 148 | if (!ent) |
| 149 | break; |
| 150 | if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) |
| 151 | continue; |
| 152 | char abort[300]; |
| 153 | snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort", |
| 154 | ent->d_name); |
| 155 | int fd = open(abort, O_WRONLY); |
| 156 | if (fd == -1) { |
| 157 | continue; |
| 158 | } |
| 159 | if (write(fd, abort, 1) < 0) { |
| 160 | } |
| 161 | close(fd); |
| 162 | } |
| 163 | closedir(dir); |
| 164 | } else { |
| 165 | } |
| 166 | while (waitpid(-1, status, __WALL) != pid) { |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | #define SYZ_HAVE_SETUP_TEST 1 |
| 171 | static void setup_test() |
| 172 | { |
| 173 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); |
| 174 | setpgrp(); |
| 175 | write_file("/proc/self/oom_score_adj", "1000"); |
| 176 | } |
| 177 | |
| 178 | struct thread_t { |
| 179 | int created, call; |
| 180 | event_t ready, done; |
| 181 | }; |
| 182 | |
| 183 | static struct thread_t threads[16]; |
| 184 | static void execute_call(int call); |
| 185 | static int running; |
| 186 | |
| 187 | static void* thr(void* arg) |
| 188 | { |
| 189 | struct thread_t* th = (struct thread_t*)arg; |
| 190 | for (;;) { |
| 191 | event_wait(&th->ready); |
| 192 | event_reset(&th->ready); |
| 193 | execute_call(th->call); |
| 194 | __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); |
| 195 | event_set(&th->done); |
| 196 | } |
| 197 | return 0; |
| 198 | } |
| 199 | |
| 200 | static void execute_one(void) |
| 201 | { |
| 202 | int i, call, thread; |
| 203 | for (call = 0; call < 3; call++) { |
| 204 | for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); |
| 205 | thread++) { |
| 206 | struct thread_t* th = &threads[thread]; |
| 207 | if (!th->created) { |
| 208 | th->created = 1; |
| 209 | event_init(&th->ready); |
| 210 | event_init(&th->done); |
| 211 | event_set(&th->done); |
| 212 | thread_start(thr, th); |
| 213 | } |
| 214 | if (!event_isset(&th->done)) |
| 215 | continue; |
| 216 | event_reset(&th->done); |
| 217 | th->call = call; |
| 218 | __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); |
| 219 | event_set(&th->ready); |
| 220 | event_timedwait(&th->done, 45); |
| 221 | break; |
| 222 | } |
| 223 | } |
| 224 | for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) |
| 225 | sleep_ms(1); |
| 226 | } |
| 227 | |
| 228 | static void execute_one(void); |
| 229 | |
| 230 | #define WAIT_FLAGS __WALL |
| 231 | |
| 232 | static void loop(void) |
| 233 | { |
| 234 | int iter; |
| 235 | for (iter = 0;; iter++) { |
| 236 | int pid = fork(); |
| 237 | if (pid < 0) |
| 238 | exit(1); |
| 239 | if (pid == 0) { |
| 240 | setup_test(); |
| 241 | execute_one(); |
| 242 | exit(0); |
| 243 | } |
| 244 | int status = 0; |
| 245 | uint64_t start = current_time_ms(); |
| 246 | for (;;) { |
| 247 | if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) |
| 248 | break; |
| 249 | sleep_ms(1); |
| 250 | if (current_time_ms() - start < 5 * 1000) |
| 251 | continue; |
| 252 | kill_and_wait(pid, &status); |
| 253 | break; |
| 254 | } |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | #ifndef __NR_io_uring_register |
| 259 | #define __NR_io_uring_register 427 |
| 260 | #endif |
| 261 | #ifndef __NR_io_uring_setup |
| 262 | #define __NR_io_uring_setup 425 |
| 263 | #endif |
Jens Axboe | 78f59df | 2019-04-23 12:05:18 -0600 | [diff] [blame] | 264 | |
| 265 | uint64_t r[1] = {0xffffffffffffffff}; |
| 266 | |
| 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 = syscall(__NR_io_uring_setup, 0x64, 0x20000040); |
| 301 | if (res != -1) |
| 302 | r[0] = res; |
| 303 | break; |
| 304 | case 1: |
| 305 | syscall(__NR_io_uring_register, (long)r[0], 0, 0, 0); |
| 306 | break; |
| 307 | case 2: |
| 308 | syscall(__NR_io_uring_register, (long)r[0], 0, 0, 0); |
| 309 | break; |
| 310 | } |
| 311 | } |
Jens Axboe | b00ba56 | 2019-10-08 12:23:38 -0600 | [diff] [blame] | 312 | |
| 313 | static void sig_int(int sig) |
| 314 | { |
| 315 | exit(0); |
| 316 | } |
| 317 | |
Jens Axboe | 78f59df | 2019-04-23 12:05:18 -0600 | [diff] [blame] | 318 | int main(void) |
| 319 | { |
Jens Axboe | b00ba56 | 2019-10-08 12:23:38 -0600 | [diff] [blame] | 320 | signal(SIGINT, sig_int); |
Jens Axboe | 459e895 | 2020-04-24 07:39:24 -0600 | [diff] [blame^] | 321 | mmap((void *) 0x20000000, 0x1000000, 3, 0x32, -1, 0); |
Jens Axboe | 78f59df | 2019-04-23 12:05:18 -0600 | [diff] [blame] | 322 | loop(); |
| 323 | return 0; |
| 324 | } |