// https://syzkaller.appspot.com/bug?id=af3a0728c8cbf6903ec2b0836441287cced00c1c // autogenerated by syzkaller (http://github.com/google/syzkaller) #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include __attribute__((noreturn)) static void doexit(int status) { volatile unsigned i; syscall(__NR_exit_group, status); for (i = 0;; i++) { } } #include #include #include #include #include #include #include #include #include #include const int kFailStatus = 67; const int kRetryStatus = 69; static void fail(const char* msg, ...) { int e = errno; va_list args; va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, " (errno %d)\n", e); doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus); } static __thread int skip_segv; static __thread jmp_buf segv_env; static void segv_handler(int sig, siginfo_t* info, void* uctx) { uintptr_t addr = (uintptr_t)info->si_addr; const uintptr_t prog_start = 1 << 20; const uintptr_t prog_end = 100 << 20; if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) && (addr < prog_start || addr > prog_end)) { _longjmp(segv_env, 1); } doexit(sig); } static void install_segv_handler() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8); syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8); memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = segv_handler; sa.sa_flags = SA_NODEFER | SA_SIGINFO; sigaction(SIGSEGV, &sa, NULL); sigaction(SIGBUS, &sa, NULL); } #define NONFAILING(...) \ { \ __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ if (_setjmp(segv_env) == 0) { \ __VA_ARGS__; \ } \ __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \ } static void use_temporary_dir() { char tmpdir_template[] = "./syzkaller.XXXXXX"; char* tmpdir = mkdtemp(tmpdir_template); if (!tmpdir) fail("failed to mkdtemp"); if (chmod(tmpdir, 0777)) fail("failed to chmod"); if (chdir(tmpdir)) fail("failed to chdir"); } extern unsigned long long procid; struct fs_image_segment { void* data; uintptr_t size; uintptr_t offset; }; #define IMAGE_MAX_SEGMENTS 4096 #define IMAGE_MAX_SIZE (129 << 20) #define SYZ_memfd_create 319 static uintptr_t syz_read_part_table(uintptr_t size, uintptr_t nsegs, uintptr_t segments) { char loopname[64], linkname[64]; int loopfd, err = 0, res = -1; uintptr_t i, j; struct fs_image_segment* segs = (struct fs_image_segment*)segments; if (nsegs > IMAGE_MAX_SEGMENTS) nsegs = IMAGE_MAX_SEGMENTS; for (i = 0; i < nsegs; i++) { if (segs[i].size > IMAGE_MAX_SIZE) segs[i].size = IMAGE_MAX_SIZE; segs[i].offset %= IMAGE_MAX_SIZE; if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size) segs[i].offset = IMAGE_MAX_SIZE - segs[i].size; if (size < segs[i].offset + segs[i].offset) size = segs[i].offset + segs[i].offset; } if (size > IMAGE_MAX_SIZE) size = IMAGE_MAX_SIZE; int memfd = syscall(SYZ_memfd_create, "syz_read_part_table", 0); if (memfd == -1) { err = errno; goto error; } if (ftruncate(memfd, size)) { err = errno; goto error_close_memfd; } for (i = 0; i < nsegs; i++) { if (pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset) < 0) { } } snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid); loopfd = open(loopname, O_RDWR); if (loopfd == -1) { err = errno; goto error_close_memfd; } if (ioctl(loopfd, LOOP_SET_FD, memfd)) { if (errno != EBUSY) { err = errno; goto error_close_loop; } ioctl(loopfd, LOOP_CLR_FD, 0); usleep(1000); if (ioctl(loopfd, LOOP_SET_FD, memfd)) { err = errno; goto error_close_loop; } } struct loop_info64 info; if (ioctl(loopfd, LOOP_GET_STATUS64, &info)) { err = errno; goto error_clear_loop; } info.lo_flags |= LO_FLAGS_PARTSCAN; if (ioctl(loopfd, LOOP_SET_STATUS64, &info)) { err = errno; goto error_clear_loop; } res = 0; for (i = 1, j = 0; i < 8; i++) { snprintf(loopname, sizeof(loopname), "/dev/loop%llup%d", procid, (int)i); struct stat statbuf; if (stat(loopname, &statbuf) == 0) { snprintf(linkname, sizeof(linkname), "./file%d", (int)j++); if (symlink(loopname, linkname)) { } } } error_clear_loop: ioctl(loopfd, LOOP_CLR_FD, 0); error_close_loop: close(loopfd); error_close_memfd: close(memfd); error: errno = err; return res; } static void loop(); static void sandbox_common() { prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); setpgrp(); setsid(); struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 160 << 20; setrlimit(RLIMIT_AS, &rlim); rlim.rlim_cur = rlim.rlim_max = 8 << 20; setrlimit(RLIMIT_MEMLOCK, &rlim); rlim.rlim_cur = rlim.rlim_max = 136 << 20; setrlimit(RLIMIT_FSIZE, &rlim); rlim.rlim_cur = rlim.rlim_max = 1 << 20; setrlimit(RLIMIT_STACK, &rlim); rlim.rlim_cur = rlim.rlim_max = 0; setrlimit(RLIMIT_CORE, &rlim); if (unshare(CLONE_NEWNS)) { } if (unshare(CLONE_NEWIPC)) { } if (unshare(0x02000000)) { } if (unshare(CLONE_NEWUTS)) { } if (unshare(CLONE_SYSVSEM)) { } } int wait_for_loop(int pid) { if (pid < 0) fail("sandbox fork failed"); int status = 0; while (waitpid(-1, &status, __WALL) != pid) { } return WEXITSTATUS(status); } static int do_sandbox_none(void) { if (unshare(CLONE_NEWPID)) { } int pid = fork(); if (pid != 0) return wait_for_loop(pid); sandbox_common(); if (unshare(CLONE_NEWNET)) { } loop(); doexit(1); } struct thread_t { int created, running, call; pthread_t th; }; static struct thread_t threads[16]; static void execute_call(int call); static int running; static int collide; static void* thr(void* arg) { struct thread_t* th = (struct thread_t*)arg; for (;;) { while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0); execute_call(th->call); __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); __atomic_store_n(&th->running, 0, __ATOMIC_RELEASE); syscall(SYS_futex, &th->running, FUTEX_WAKE); } return 0; } static void execute(int num_calls) { int call, thread; running = 0; for (call = 0; call < num_calls; call++) { for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) { struct thread_t* th = &threads[thread]; if (!th->created) { th->created = 1; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 128 << 10); pthread_create(&th->th, &attr, thr, th); } if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) { th->call = call; __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); __atomic_store_n(&th->running, 1, __ATOMIC_RELEASE); syscall(SYS_futex, &th->running, FUTEX_WAKE); if (collide && call % 2) break; struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 20 * 1000 * 1000; syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts); if (__atomic_load_n(&running, __ATOMIC_RELAXED)) usleep((call == num_calls - 1) ? 10000 : 1000); break; } } } } uint64_t r[6] = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0x0, 0xffffffffffffffff}; unsigned long long procid; void execute_call(int call) { long res; switch (call) { case 0: NONFAILING(memcpy((void*)0x20000000, "/dev/full", 10)); res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20000000, 0x28000, 0); if (res != -1) r[0] = res; break; case 1: syscall(__NR_ioctl, r[0], 0x4b34, 0x401); break; case 2: syscall(__NR_ioctl, r[0], 0x4b65, 0x2000000000); break; case 3: res = syscall(__NR_socketpair, 9, 0x800, 2, 0x20000040); if (res != -1) { NONFAILING(r[1] = *(uint32_t*)0x20000040); NONFAILING(r[2] = *(uint32_t*)0x20000044); } break; case 4: syscall(__NR_ioctl, r[0], 0x4b64, 0x20000080); break; case 5: NONFAILING(memcpy( (void*)0x200000c0, "\x69\x13\x10\x66\x7b\xe5\xef\x88\x6a\x50\xc5\xd3\xc1\xfc\x67\x2e", 16)); syscall(__NR_setsockopt, r[0], 6, 0x21, 0x200000c0, 0x10); break; case 6: NONFAILING(memcpy((void*)0x20000100, "./file0", 8)); syscall(__NR_readlink, 0x20000100, 0x20000140, 0x1000); break; case 7: NONFAILING(*(uint32_t*)0x20001180 = 0x14); syscall(__NR_getsockopt, r[2], 6, 0x1d, 0x20001140, 0x20001180); break; case 8: NONFAILING(*(uint32_t*)0x200011c0 = 0xf7); syscall(__NR_ioctl, r[1], 0x5418, 0x200011c0); break; case 9: syscall(__NR_ioctl, r[1], 0x4b65, 0x3f); break; case 10: syscall(__NR_ioctl, r[0], 0x4b30, 7); break; case 11: syscall(__NR_flistxattr, r[1], 0x20001200, 0x1000); break; case 12: res = syscall(__NR_semget, 0, 0, 0x20); if (res != -1) r[3] = res; break; case 13: NONFAILING(*(uint16_t*)0x20002200 = 0x3f); NONFAILING(*(uint16_t*)0x20002202 = 1); NONFAILING(*(uint16_t*)0x20002204 = 4); syscall(__NR_semctl, r[3], 0, 0x11, 0x20002200); break; case 14: syscall(__NR_ioctl, r[1], 0x4b64, 0x20002240); break; case 15: NONFAILING(memcpy((void*)0x20002280, "./file1", 8)); NONFAILING(memcpy((void*)0x200022c0, "./file0", 8)); syscall(__NR_symlink, 0x20002280, 0x200022c0); break; case 16: NONFAILING(*(uint64_t*)0x20003740 = 0x20002300); NONFAILING(*(uint64_t*)0x20003748 = 0); NONFAILING(*(uint64_t*)0x20003750 = 1); NONFAILING(*(uint64_t*)0x20003758 = 0x200023c0); NONFAILING(*(uint64_t*)0x20003760 = 0); NONFAILING(*(uint64_t*)0x20003768 = 0x8000); NONFAILING(*(uint64_t*)0x20003770 = 0x20002440); NONFAILING(*(uint64_t*)0x20003778 = 0); NONFAILING(*(uint64_t*)0x20003780 = 3); NONFAILING(*(uint64_t*)0x20003788 = 0x200024c0); NONFAILING(*(uint64_t*)0x20003790 = 0); NONFAILING(*(uint64_t*)0x20003798 = 0x1f); NONFAILING(*(uint64_t*)0x200037a0 = 0x20002540); NONFAILING(*(uint64_t*)0x200037a8 = 0); NONFAILING(*(uint64_t*)0x200037b0 = 0x10000); NONFAILING(*(uint64_t*)0x200037b8 = 0x20002640); NONFAILING(*(uint64_t*)0x200037c0 = 0); NONFAILING(*(uint64_t*)0x200037c8 = 0xfffffffffffffff9); NONFAILING(*(uint64_t*)0x200037d0 = 0x20003640); NONFAILING(*(uint64_t*)0x200037d8 = 0); NONFAILING(*(uint64_t*)0x200037e0 = 0xffffffffffffff01); syz_read_part_table(0x5f27ecd0, 7, 0x20003740); break; case 17: res = syscall(__NR_ioctl, r[1], 0x8904, 0x20003800); if (res != -1) NONFAILING(r[4] = *(uint32_t*)0x20003800); break; case 18: syscall(__NR_fcntl, r[0], 8, r[4]); break; case 19: syscall(__NR_ioctl, r[0], 0x5428); break; case 20: NONFAILING(*(uint16_t*)0x20003840 = 0); NONFAILING(*(uint16_t*)0x20003842 = 9); NONFAILING(*(uint16_t*)0x20003844 = 1); syscall(__NR_ioctl, r[1], 0x5609, 0x20003840); break; case 21: NONFAILING(memcpy((void*)0x20003880, "/dev/ptmx", 10)); res = syscall(__NR_openat, 0xffffffffffffff9c, 0x20003880, 0x40000, 0); if (res != -1) r[5] = res; break; case 22: syscall(__NR_read, r[5], 0x200038c0, 0x83); break; } } void loop() { execute(23); collide = 1; execute(23); } int main() { syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0); install_segv_handler(); use_temporary_dir(); do_sandbox_none(); return 0; }