lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAOQ4uxg+RveBHjgui_HjCasYGor3JNeuv-UroR=5j4n6TgRd7w@mail.gmail.com>
Date: Wed, 13 Mar 2024 15:14:21 +0200
From: Amir Goldstein <amir73il@...il.com>
To: Weiß, Simone <Simone.Weiss@...ktrobit.com>
Cc: "miklos@...redi.hu" <miklos@...redi.hu>, 
	"linux-unionfs@...r.kernel.org" <linux-unionfs@...r.kernel.org>, 
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
Subject: Re: possible deadlock in ovl_llseek 27c1936af506

On Tue, Mar 12, 2024 at 9:10 AM Weiß, Simone
<Simone.Weiss@...ktrobit.com> 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@...hat.com>
> 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;
>
> }

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ