On Tue, Mar 12, 2024 at 9:10 AM Weiß, Simone <Simone.Weiss@xxxxxxxxxxxxxx> wrote: > > Dear Miklos and Amir, > > For some experimentation, I have been running fuzzing campaigns and I > noticed a possible deadlock in ovl_llseek . > > As there is a C reproducer, it could be bisected being introduced with: > > commit 27c1936af5068b5367078a65df6a3d4de3e94e9a > Author: Miklos Szeredi <mszeredi@xxxxxxxxxx> > Date: Mon Apr 12 12:00:37 2021 +0200 > > ovl: allow upperdir inside lowerdir > > commit 708fa01597fa002599756bf56a96d0de1677375c upstream. > > Commit 146d62e5a586 ("ovl: detect overlapping layers") made sure we don't > have overlapping layers, but it also broke the arguably valid use case of > > mount -olowerdir=/,upperdir=/subdir,.. > > where upperdir overlaps lowerdir on the same filesystem. This has been > causing regressions. > > Revert the check, but only for the specific case where upperdir and/or > workdir are subdirectories of lowerdir. Any other overlap (e.g. lowerdir > is subdirectory of upperdir, etc) case is crazy, so leave the check in > place for those. > > Overlaps are detected at lookup time too, so reverting the mount time check > should be safe. > > It was reproducible on v5.10.212 and a syz-crush check also found crashes on > v6.8-rc1. > > The reason for this report is calling llseek() on lower ovl from ovl_copy_up_data() when ovl_copy_up_data() is called with upper inode lock and the lower ovl uses the same upper fs. It looks to me like the possible deadlock should have been solved by commit c63e56a4a652 ovl: do not open/llseek lower file with upper sb_writers held that moved ovl_copy_up_data() out of the inode_lock() scope. I am not sure what the statement "a syz-crush check also found crashes on v6.8-rc1." means - does it mean that this reproducer produced this same lockdep warning on upstream kernel? Thanks, Amir. > The C reproducer is automatically generated by syzkaller and included below. > > If you need any further information, just let me know. > > Regards, > Simone > > Log: > ====================================================== > WARNING: possible circular locking dependency detected > 5.10.34-eb-corbos-standard-syzkaller #0 Not tainted > ------------------------------------------------------ > syz-executor175/7735 is trying to acquire lock: > ffff00000c54a0a0 > (&ovl_i_lock_key[depth]){+.+.}-{3:3}, at: ovl_inode_lock > fs/overlayfs/overlayfs.h:362 [inline] > (&ovl_i_lock_key[depth]){+.+.}-{3:3}, at: ovl_llseek+0xec/0x194 > fs/overlayfs/file.c:207 > > but task is already holding lock: > ffff00000c60eca0 (&sb->s_type->i_mutex_key#15/5){+.+.}-{3:3}, at: > inode_lock_nested include/linux/fs.h:809 [inline] > ffff00000c60eca0 (&sb->s_type->i_mutex_key#15/5){+.+.}-{3:3}, at: > lock_rename+0x10c/0x144 fs/namei.c:2772 > > which lock already depends on the new lock. > > > the existing dependency chain (in reverse order) is: > > -> #2 (&sb->s_type->i_mutex_key#15/5 > ){+.+.}-{3:3}: > __lock_release kernel/locking/lockdep.c:5160 [inline] > lock_release+0x244/0x390 kernel/locking/lockdep.c:5464 > up_write+0x4c/0x154 kernel/locking/rwsem.c:1609 > inode_unlock include/linux/fs.h:779 [inline] > unlock_rename+0x28/0x60 fs/namei.c:2779 > ovl_workdir_ok fs/overlayfs/super.c:915 [inline] > ovl_get_workdir fs/overlayfs/super.c:1405 [inline] > ovl_fill_super+0x62c/0x28d0 fs/overlayfs/super.c:1965 > mount_nodev+0x70/0xf0 fs/super.c:1465 > ovl_mount+0x3c/0x50 fs/overlayfs/super.c:2050 > legacy_get_tree+0x34/0xb0 fs/fs_context.c:592 > vfs_get_tree+0x34/0xe0 fs/super.c:1549 > do_new_mount fs/namespace.c:2881 [inline] > path_mount+0xd50/0x1600 fs/namespace.c:3211 > do_mount fs/namespace.c:3224 [inline] > __do_sys_mount fs/namespace.c:3432 [inline] > __se_sys_mount fs/namespace.c:3409 [inline] > __arm64_sys_mount+0x680/0x7d0 fs/namespace.c:3409 > __invoke_syscall arch/arm64/kernel/syscall.c:36 [inline] > invoke_syscall arch/arm64/kernel/syscall.c:48 [inline] > el0_svc_common arch/arm64/kernel/syscall.c:158 [inline] > do_el0_svc+0xe0/0x340 arch/arm64/kernel/syscall.c:197 > el0_svc+0x24/0x34 arch/arm64/kernel/entry-common.c:367 > el0_sync_handler+0xec/0x210 arch/arm64/kernel/entry-common.c:383 > el0_sync+0x17c/0x180 arch/arm64/kernel/entry.S:672 > > -> #1 (&type->s_vfs_rename_key){+.+.}-{3:3}: > lock_acquire+0x68/0x84 kernel/locking/lockdep.c:5417 > __mutex_lock_common kernel/locking/mutex.c:959 [inline] > __mutex_lock+0x84/0x730 kernel/locking/mutex.c:1106 > mutex_lock_nested+0x40/0x50 kernel/locking/mutex.c:1121 > lock_rename+0x3c/0x144 fs/namei.c:2755 > ovl_copy_up_workdir fs/overlayfs/copy_up.c:595 [inline] > ovl_do_copy_up fs/overlayfs/copy_up.c:746 [inline] > ovl_copy_up_one+0x434/0x12ec fs/overlayfs/copy_up.c:916 > ovl_copy_up_flags+0x100/0x164 fs/overlayfs/copy_up.c:961 > ovl_maybe_copy_up+0x104/0x14c fs/overlayfs/copy_up.c:993 > ovl_open+0x4c/0x110 fs/overlayfs/file.c:154 > do_dentry_open+0x2a0/0x5c0 fs/open.c:817 > vfs_open+0x38/0x50 fs/open.c:931 > do_open fs/namei.c:3243 [inline] > path_openat+0xc88/0x1050 fs/namei.c:3360 > do_filp_open+0x8c/0x170 fs/namei.c:3387 > do_sys_openat2+0xf4/0x240 fs/open.c:1172 > __do_sys_openat2 fs/open.c:1227 [inline] > __se_sys_openat2 fs/open.c:1207 [inline] > __arm64_sys_openat2+0x304/0x410 fs/open.c:1207 > __invoke_syscall arch/arm64/kernel/syscall.c:36 [inline] > invoke_syscall arch/arm64/kernel/syscall.c:48 [inline] > el0_svc_common arch/arm64/kernel/syscall.c:158 [inline] > do_el0_svc+0xe0/0x340 arch/arm64/kernel/syscall.c:197 > el0_svc+0x24/0x34 arch/arm64/kernel/entry-common.c:367 > el0_sync_handler+0xec/0x210 arch/arm64/kernel/entry-common.c:383 > el0_sync+0x17c/0x180 arch/arm64/kernel/entry.S:672 > > -> #0 (&ovl_i_lock_key[depth]){+.+.}-{3:3}: > check_prev_add kernel/locking/lockdep.c:2869 [inline] > check_prevs_add kernel/locking/lockdep.c:2994 [inline] > validate_chain kernel/locking/lockdep.c:3609 [inline] > __lock_acquire+0x10ec/0x18a4 kernel/locking/lockdep.c:4834 > lock_acquire.part.0+0xec/0x2e0 kernel/locking/lockdep.c:5444 > lock_acquire+0x68/0x84 kernel/locking/lockdep.c:5417 > __mutex_lock_common kernel/locking/mutex.c:959 [inline] > __mutex_lock+0x84/0x730 kernel/locking/mutex.c:1106 > mutex_lock_nested+0x40/0x50 kernel/locking/mutex.c:1121 > ovl_inode_lock fs/overlayfs/overlayfs.h:362 [inline] > ovl_llseek+0xec/0x194 fs/overlayfs/file.c:207 > vfs_llseek+0x60/0x80 fs/read_write.c:300 > ovl_copy_up_data+0x21c/0x390 fs/overlayfs/copy_up.c:199 > ovl_copy_up_inode+0x258/0x2b4 fs/overlayfs/copy_up.c:507 > ovl_copy_up_workdir fs/overlayfs/copy_up.c:609 [inline] > ovl_do_copy_up fs/overlayfs/copy_up.c:746 [inline] > ovl_copy_up_one+0x4cc/0x12ec fs/overlayfs/copy_up.c:916 > ovl_copy_up_flags+0x100/0x164 fs/overlayfs/copy_up.c:961 > ovl_maybe_copy_up+0x104/0x14c fs/overlayfs/copy_up.c:993 > ovl_open+0x4c/0x110 fs/overlayfs/file.c:154 > do_dentry_open+0x2a0/0x5c0 fs/open.c:817 > vfs_open+0x38/0x50 fs/open.c:931 > do_open fs/namei.c:3243 [inline] > path_openat+0xc88/0x1050 fs/namei.c:3360 > do_filp_open+0x8c/0x170 fs/namei.c:3387 > do_sys_openat2+0xf4/0x240 fs/open.c:1172 > __do_sys_openat2 fs/open.c:1227 [inline] > __se_sys_openat2 fs/open.c:1207 [inline] > __arm64_sys_openat2+0x304/0x410 fs/open.c:1207 > __invoke_syscall arch/arm64/kernel/syscall.c:36 [inline] > invoke_syscall arch/arm64/kernel/syscall.c:48 [inline] > el0_svc_common arch/arm64/kernel/syscall.c:158 [inline] > do_el0_svc+0xe0/0x340 arch/arm64/kernel/syscall.c:197 > el0_svc+0x24/0x34 arch/arm64/kernel/entry-common.c:367 > el0_sync_handler+0xec/0x210 arch/arm64/kernel/entry-common.c:383 > el0_sync+0x17c/0x180 arch/arm64/kernel/entry.S:672 > > other info that might help us debug this: > > Chain exists of: > &ovl_i_lock_key[depth] --> &type->s_vfs_rename_key --> &sb->s_type- > >i_mutex_key#15/5 > > Possible unsafe locking scenario: > > CPU0 CPU1 > ---- ---- > lock(&sb->s_type->i_mutex_key#15/5); > lock(&type->s_vfs_rename_key); > lock(&sb->s_type->i_mutex_key#15/5); > lock(&ovl_i_lock_key[depth]); > > *** DEADLOCK *** > > 5 locks held by syz-executor175/7735: > #0: ffff000005302438 (sb_writers#9){.+.+}-{0:0}, at: __sb_start_write > include/linux/fs.h:1594 [inline] > #0: ffff000005302438 (sb_writers#9){.+.+}-{0:0}, at: sb_start_write > include/linux/fs.h:1664 [inline] > #0: ffff000005302438 (sb_writers#9){.+.+}-{0:0}, at: mnt_want_write+0x24/0x80 > fs/namespace.c:354 > #1: ffff00000c54bcc0 (&ovl_i_lock_key[depth]#2){+.+.}-{3:3}, at: > ovl_inode_lock_interruptible fs/overlayfs/overlayfs.h:367 [inline] > #1: ffff00000c54bcc0 (&ovl_i_lock_key[depth]#2){+.+.}-{3:3}, at: > ovl_copy_up_start+0x34/0x160 fs/overlayfs/util.c:533 > #2: ffff000005302720 (&type->s_vfs_rename_key){+.+.}-{3:3}, at: > lock_rename+0x3c/0x144 fs/namei.c:2755 > #3: ffff000006711110 (&sb->s_type->i_mutex_key#15/1){+.+.}-{3:3}, at: > inode_lock_nested include/linux/fs.h:809 [inline] > #3: ffff000006711110 (&sb->s_type->i_mutex_key#15/1){+.+.}-{3:3}, at: > lock_rename+0xfc/0x144 fs/namei.c:2771 > #4: ffff00000c60eca0 (&sb->s_type->i_mutex_key#15/5){+.+.}-{3:3}, at: > inode_lock_nested include/linux/fs.h:809 [inline] > #4: ffff00000c60eca0 (&sb->s_type->i_mutex_key#15/5){+.+.}-{3:3}, at: > lock_rename+0x10c/0x144 fs/namei.c:2772 > > stack backtrace: > CPU: 0 PID: 7735 Comm: syz-executor175 Not tainted 5.10.34-eb-corbos-standard- > syzkaller #0 > Hardware name: linux,dummy-virt (DT) > Call trace: > dump_backtrace+0x0/0x2e0 arch/arm64/include/asm/atomic_ll_sc.h:222 > show_stack+0x2c/0x40 arch/arm64/kernel/stacktrace.c:196 > __dump_stack lib/dump_stack.c:77 [inline] > dump_stack+0x1d4/0x26c lib/dump_stack.c:118 > print_circular_bug+0x1f8/0x200 kernel/locking/lockdep.c:1997 > check_noncircular+0x100/0x114 kernel/locking/lockdep.c:2118 > check_prev_add kernel/locking/lockdep.c:2869 [inline] > check_prevs_add kernel/locking/lockdep.c:2994 [inline] > validate_chain kernel/locking/lockdep.c:3609 [inline] > __lock_acquire+0x10ec/0x18a4 kernel/locking/lockdep.c:4834 > lock_acquire.part.0+0xec/0x2e0 kernel/locking/lockdep.c:5444 > lock_acquire+0x68/0x84 kernel/locking/lockdep.c:5417 > __mutex_lock_common kernel/locking/mutex.c:959 [inline] > __mutex_lock+0x84/0x730 kernel/locking/mutex.c:1106 > mutex_lock_nested+0x40/0x50 kernel/locking/mutex.c:1121 > ovl_inode_lock fs/overlayfs/overlayfs.h:362 [inline] > ovl_llseek+0xec/0x194 fs/overlayfs/file.c:207 > vfs_llseek+0x60/0x80 fs/read_write.c:300 > ovl_copy_up_data+0x21c/0x390 fs/overlayfs/copy_up.c:199 > ovl_copy_up_inode+0x258/0x2b4 fs/overlayfs/copy_up.c:507 > ovl_copy_up_workdir fs/overlayfs/copy_up.c:609 [inline] > ovl_do_copy_up fs/overlayfs/copy_up.c:746 [inline] > ovl_copy_up_one+0x4cc/0x12ec fs/overlayfs/copy_up.c:916 > ovl_copy_up_flags+0x100/0x164 fs/overlayfs/copy_up.c:961 > ovl_maybe_copy_up+0x104/0x14c fs/overlayfs/copy_up.c:993 > ovl_open+0x4c/0x110 fs/overlayfs/file.c:154 > do_dentry_open+0x2a0/0x5c0 fs/open.c:817 > vfs_open+0x38/0x50 fs/open.c:931 > do_open fs/namei.c:3243 [inline] > path_openat+0xc88/0x1050 fs/namei.c:3360 > do_filp_open+0x8c/0x170 fs/namei.c:3387 > do_sys_openat2+0xf4/0x240 fs/open.c:1172 > __do_sys_openat2 fs/open.c:1227 [inline] > __se_sys_openat2 fs/open.c:1207 [inline] > __arm64_sys_openat2+0x304/0x410 fs/open.c:1207 > __invoke_syscall arch/arm64/kernel/syscall.c:36 [inline] > invoke_syscall arch/arm64/kernel/syscall.c:48 [inline] > el0_svc_common arch/arm64/kernel/syscall.c:158 [inline] > do_el0_svc+0xe0/0x340 arch/arm64/kernel/syscall.c:197 > el0_svc+0x24/0x34 arch/arm64/kernel/entry-common.c:367 > el0_sync_handler+0xec/0x210 arch/arm64/kernel/entry-common.c:383 > el0_sync+0x17c/0x180 arch/arm64/kernel/entry.S:672 > > > C Reproducer: > > // https://None.appspot.com/bug?id=f10e9988ed129179c80858a403259185ef332f5d > // autogenerated by syzkaller (https://github.com/google/syzkaller) > > #define _GNU_SOURCE > > #include <dirent.h> > #include <endian.h> > #include <errno.h> > #include <fcntl.h> > #include <pthread.h> > #include <signal.h> > #include <stdarg.h> > #include <stdbool.h> > #include <stdint.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <sys/ioctl.h> > #include <sys/mount.h> > #include <sys/prctl.h> > #include <sys/stat.h> > #include <sys/syscall.h> > #include <sys/types.h> > #include <sys/wait.h> > #include <time.h> > #include <unistd.h> > > #include <linux/futex.h> > > #ifndef __NR_chdir > #define __NR_chdir 49 > #endif > #ifndef __NR_mkdirat > #define __NR_mkdirat 34 > #endif > #ifndef __NR_mmap > #define __NR_mmap 222 > #endif > #ifndef __NR_mount > #define __NR_mount 40 > #endif > #ifndef __NR_openat > #define __NR_openat 56 > #endif > #ifndef __NR_openat2 > #define __NR_openat2 437 > #endif > #ifndef __NR_write > #define __NR_write 64 > #endif > > static unsigned long long procid; > > static void sleep_ms(uint64_t ms) > { > usleep(ms * 1000); > } > > static uint64_t current_time_ms(void) > { > struct timespec ts; > if (clock_gettime(CLOCK_MONOTONIC, &ts)) > exit(1); > return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000; > } > > static void use_temporary_dir(void) > { > char tmpdir_template[] = "./syzkaller.XXXXXX"; > char* tmpdir = mkdtemp(tmpdir_template); > if (!tmpdir) > exit(1); > if (chmod(tmpdir, 0777)) > exit(1); > if (chdir(tmpdir)) > exit(1); > } > > static void thread_start(void* (*fn)(void*), void* arg) > { > pthread_t th; > pthread_attr_t attr; > pthread_attr_init(&attr); > pthread_attr_setstacksize(&attr, 128 << 10); > int i = 0; > for (; i < 100; i++) { > if (pthread_create(&th, &attr, fn, arg) == 0) { > pthread_attr_destroy(&attr); > return; > } > if (errno == EAGAIN) { > usleep(50); > continue; > } > break; > } > exit(1); > } > > typedef struct { > int state; > } event_t; > > static void event_init(event_t* ev) > { > ev->state = 0; > } > > static void event_reset(event_t* ev) > { > ev->state = 0; > } > > static void event_set(event_t* ev) > { > if (ev->state) > exit(1); > __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE); > syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000); > } > > static void event_wait(event_t* ev) > { > while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) > syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0); > } > > static int event_isset(event_t* ev) > { > return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE); > } > > static int event_timedwait(event_t* ev, uint64_t timeout) > { > uint64_t start = current_time_ms(); > uint64_t now = start; > for (;;) { > uint64_t remain = timeout - (now - start); > struct timespec ts; > ts.tv_sec = remain / 1000; > ts.tv_nsec = (remain % 1000) * 1000 * 1000; > syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts); > if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) > return 1; > now = current_time_ms(); > if (now - start > timeout) > return 0; > } > } > > static bool write_file(const char* file, const char* what, ...) > { > char buf[1024]; > va_list args; > va_start(args, what); > vsnprintf(buf, sizeof(buf), what, args); > va_end(args); > buf[sizeof(buf) - 1] = 0; > int len = strlen(buf); > int fd = open(file, O_WRONLY | O_CLOEXEC); > if (fd == -1) > return false; > if (write(fd, buf, len) != len) { > int err = errno; > close(fd); > errno = err; > return false; > } > close(fd); > return true; > } > > #define FS_IOC_SETFLAGS _IOW('f', 2, long) > static void remove_dir(const char* dir) > { > int iter = 0; > DIR* dp = 0; > retry: > while (umount2(dir, MNT_DETACH | UMOUNT_NOFOLLOW) == 0) { > } > dp = opendir(dir); > if (dp == NULL) { > if (errno == EMFILE) { > exit(1); > } > exit(1); > } > struct dirent* ep = 0; > while ((ep = readdir(dp))) { > if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) > continue; > char filename[FILENAME_MAX]; > snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name); > while (umount2(filename, MNT_DETACH | UMOUNT_NOFOLLOW) == 0) { > } > struct stat st; > if (lstat(filename, &st)) > exit(1); > if (S_ISDIR(st.st_mode)) { > remove_dir(filename); > continue; > } > int i; > for (i = 0;; i++) { > if (unlink(filename) == 0) > break; > if (errno == EPERM) { > int fd = open(filename, O_RDONLY); > if (fd != -1) { > long flags = 0; > if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) { > } > close(fd); > continue; > } > } > if (errno == EROFS) { > break; > } > if (errno != EBUSY || i > 100) > exit(1); > if (umount2(filename, MNT_DETACH | UMOUNT_NOFOLLOW)) > exit(1); > } > } > closedir(dp); > for (int i = 0;; i++) { > if (rmdir(dir) == 0) > break; > if (i < 100) { > if (errno == EPERM) { > int fd = open(dir, O_RDONLY); > if (fd != -1) { > long flags = 0; > if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) { > } > close(fd); > continue; > } > } > if (errno == EROFS) { > break; > } > if (errno == EBUSY) { > if (umount2(dir, MNT_DETACH | UMOUNT_NOFOLLOW)) > exit(1); > continue; > } > if (errno == ENOTEMPTY) { > if (iter < 100) { > iter++; > goto retry; > } > } > } > exit(1); > } > } > > static void kill_and_wait(int pid, int* status) > { > kill(-pid, SIGKILL); > kill(pid, SIGKILL); > for (int i = 0; i < 100; i++) { > if (waitpid(-1, status, WNOHANG | __WALL) == pid) > return; > usleep(1000); > } > DIR* dir = opendir("/sys/fs/fuse/connections"); > if (dir) { > for (;;) { > struct dirent* ent = readdir(dir); > if (!ent) > break; > if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) > continue; > char abort[300]; > snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort", > ent->d_name); > int fd = open(abort, O_WRONLY); > if (fd == -1) { > continue; > } > if (write(fd, abort, 1) < 0) { > } > close(fd); > } > closedir(dir); > } else { > } > while (waitpid(-1, status, __WALL) != pid) { > } > } > > static void setup_test() > { > prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); > setpgrp(); > write_file("/proc/self/oom_score_adj", "1000"); > if (symlink("/dev/binderfs", "./binderfs")) { > } > } > > struct thread_t { > int created, call; > event_t ready, done; > }; > > static struct thread_t threads[16]; > static void execute_call(int call); > static int running; > > static void* thr(void* arg) > { > struct thread_t* th = (struct thread_t*)arg; > for (;;) { > event_wait(&th->ready); > event_reset(&th->ready); > execute_call(th->call); > __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED); > event_set(&th->done); > } > return 0; > } > > static void execute_one(void) > { > int i, call, thread; > for (call = 0; call < 12; call++) { > for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0])); > thread++) { > struct thread_t* th = &threads[thread]; > if (!th->created) { > th->created = 1; > event_init(&th->ready); > event_init(&th->done); > event_set(&th->done); > thread_start(thr, th); > } > if (!event_isset(&th->done)) > continue; > event_reset(&th->done); > th->call = call; > __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED); > event_set(&th->ready); > event_timedwait(&th->done, 50); > break; > } > } > for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++) > sleep_ms(1); > } > > static void execute_one(void); > > #define WAIT_FLAGS __WALL > > static void loop(void) > { > int iter = 0; > for (;; iter++) { > char cwdbuf[32]; > sprintf(cwdbuf, "./%d", iter); > if (mkdir(cwdbuf, 0777)) > exit(1); > int pid = fork(); > if (pid < 0) > exit(1); > if (pid == 0) { > if (chdir(cwdbuf)) > exit(1); > setup_test(); > execute_one(); > exit(0); > } > int status = 0; > uint64_t start = current_time_ms(); > for (;;) { > if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) > break; > sleep_ms(1); > if (current_time_ms() - start < 5000) > continue; > kill_and_wait(pid, &status); > break; > } > remove_dir(cwdbuf); > } > } > > uint64_t r[1] = {0xffffffffffffffff}; > > void execute_call(int call) > { > intptr_t res = 0; > switch (call) { > case 0: > memcpy((void*)0x20000000, "./file0\000", 8); > syscall(__NR_mkdirat, /*fd=*/0xffffff9c, /*path=*/0x20000000ul, > /*mode=*/0ul); > break; > case 1: > memcpy((void*)0x20000080, "./file0\000", 8); > memcpy((void*)0x200000c0, "ramfs\000", 6); > syscall(__NR_mount, /*src=*/0ul, /*dst=*/0x20000080ul, > /*type=*/0x200000c0ul, /*flags=*/0ul, /*data=*/0ul); > break; > case 2: > memcpy((void*)0x20000240, "./file0/file0\000", 14); > syscall(__NR_mkdirat, /*fd=*/0xffffff9c, /*path=*/0x20000240ul, > /*mode=*/0ul); > break; > case 3: > memcpy((void*)0x20000480, "./file0/file0\000", 14); > syscall(__NR_chdir, /*dir=*/0x20000480ul); > break; > case 4: > memcpy((void*)0x20000180, "./file0\000", 8); > syscall(__NR_mkdirat, /*fd=*/0xffffff9c, /*path=*/0x20000180ul, > /*mode=*/0ul); > break; > case 5: > memcpy((void*)0x20000080, "./file0/file1\000", 14); > res = > syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x20000080ul, > /*flags=O_CREAT|O_CLOEXEC|O_RDWR*/ 0x80042ul, /*mode=*/0ul); > if (res != -1) > r[0] = res; > break; > case 6: > syscall(__NR_write, /*fd=*/r[0], /*data=*/0x20000980ul, /*len=*/0x58ul); > break; > case 7: > memcpy((void*)0x200000c0, "./file0/file0\000", 14); > syscall(__NR_mkdirat, /*fd=*/0xffffff9c, /*path=*/0x200000c0ul, > /*mode=*/0ul); > break; > case 8: > memcpy((void*)0x20000280, "./file1\000", 8); > syscall(__NR_mkdirat, /*fd=*/0xffffff9c, /*path=*/0x20000280ul, > /*mode=*/0ul); > break; > case 9: > memcpy((void*)0x20000200, "./file0\000", 8); > memcpy((void*)0x200001c0, "overlay\000", 8); > memcpy((void*)0x20000340, "lowerdir", 8); > *(uint8_t*)0x20000348 = 0x3d; > memcpy((void*)0x20000349, "./file0", 7); > *(uint8_t*)0x20000350 = 0x2c; > memcpy((void*)0x20000351, "workdir", 7); > *(uint8_t*)0x20000358 = 0x3d; > memcpy((void*)0x20000359, "./file1", 7); > *(uint8_t*)0x20000360 = 0x2c; > memcpy((void*)0x20000361, "upperdir", 8); > *(uint8_t*)0x20000369 = 0x3d; > memcpy((void*)0x2000036a, "./file0/file0", 13); > *(uint8_t*)0x20000377 = 0x2c; > *(uint8_t*)0x20000378 = 0; > syscall(__NR_mount, /*src=*/0ul, /*dst=*/0x20000200ul, > /*type=*/0x200001c0ul, /*flags=*/0ul, /*opts=*/0x20000340ul); > break; > case 10: > memcpy((void*)0x20000200, "./file0\000", 8); > memcpy((void*)0x200001c0, "overlay\000", 8); > memcpy((void*)0x20000340, "lowerdir", 8); > *(uint8_t*)0x20000348 = 0x3d; > memcpy((void*)0x20000349, "./file0", 7); > *(uint8_t*)0x20000350 = 0x2c; > memcpy((void*)0x20000351, "workdir", 7); > *(uint8_t*)0x20000358 = 0x3d; > memcpy((void*)0x20000359, "./file1", 7); > *(uint8_t*)0x20000360 = 0x2c; > memcpy((void*)0x20000361, "upperdir", 8); > *(uint8_t*)0x20000369 = 0x3d; > memcpy((void*)0x2000036a, "./file0/file0", 13); > *(uint8_t*)0x20000377 = 0x2c; > *(uint8_t*)0x20000378 = 0; > syscall(__NR_mount, /*src=*/0ul, /*dst=*/0x20000200ul, > /*type=*/0x200001c0ul, /*flags=*/0ul, /*opts=*/0x20000340ul); > break; > case 11: > memcpy((void*)0x20000100, "./file0/file1\000", 14); > *(uint64_t*)0x20000140 = 0x80041; > *(uint64_t*)0x20000148 = 0; > *(uint64_t*)0x20000150 = 0; > syscall(__NR_openat2, /*fd=*/0xffffffffffffff9cul, /*file=*/0x20000100ul, > /*how=*/0x20000140ul, /*size=*/0x18ul); > break; > } > } > int main(void) > { > syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul, > /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1, > /*offset=*/0ul); > syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, > /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul, > /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1, > /*offset=*/0ul); > syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul, > /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x32ul, /*fd=*/-1, > /*offset=*/0ul); > for (procid = 0; procid < 6; procid++) { > if (fork() == 0) { > use_temporary_dir(); > loop(); > } > } > sleep(1000000); > return 0; > > }