On 03.08.2018 13:59, Kirill Tkhai wrote: > On 03.08.2018 13:31, David Howells wrote: >> The reproducer can be reduced to: >> >> #define _GNU_SOURCE >> #include <endian.h> >> #include <stdint.h> >> #include <string.h> >> #include <stdio.h> >> #include <sys/syscall.h> >> #include <sys/stat.h> >> #include <sys/mount.h> >> #include <unistd.h> >> #include <fcntl.h> >> >> const char path[] = "./file0"; >> >> int main() >> { >> mkdir(path, 0); >> mount(path, path, "cgroup2", 0, 0); >> chroot(path); >> umount2(path, 0); >> return 0; >> } >> >> and I've found two bugs (see attached patch). The issue is that >> do_remount_sb() is called with fc == NULL from umount(), but both >> cgroup_reconfigure() and do_remount_sb() dereference fc unconditionally. >> >> But! I'm not sure why the reproducer works at all because the umount2() call >> is *after* the chroot, so should fail on ENOENT before it even gets that far. >> In fact, umount2() can be called multiple times, apparently successfully, and >> doesn't actually unmount anything. > > Before I also try to check why it works; just reporting you that the patch > works the problem in my environment. Thanks, David. patch *fixes* the problem > >> --- >> diff --git a/fs/super.c b/fs/super.c >> index 3fe5d12b7697..321fbc244570 100644 >> --- a/fs/super.c >> +++ b/fs/super.c >> @@ -978,7 +978,10 @@ int do_remount_sb(struct super_block *sb, int sb_flags, void *data, >> sb->s_op->remount_fs) { >> if (sb->s_op->reconfigure) { >> retval = sb->s_op->reconfigure(sb, fc); >> - sb_flags = fc->sb_flags; >> + if (fc) >> + sb_flags = fc->sb_flags; >> + else >> + sb_flags = sb->s_flags; >> if (retval == 0) >> security_sb_reconfigure(fc); >> } else { >> diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c >> index f3238f38d152..48275fdce053 100644 >> --- a/kernel/cgroup/cgroup.c >> +++ b/kernel/cgroup/cgroup.c >> @@ -1796,9 +1796,11 @@ static void apply_cgroup_root_flags(unsigned int root_flags) >> >> static int cgroup_reconfigure(struct kernfs_root *kf_root, struct fs_context *fc) >> { >> - struct cgroup_fs_context *ctx = cgroup_fc2context(fc); >> + if (fc) { >> + struct cgroup_fs_context *ctx = cgroup_fc2context(fc); >> >> - apply_cgroup_root_flags(ctx->flags); >> + apply_cgroup_root_flags(ctx->flags); >> + } >> return 0; >> } >> >>