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. > --- > 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; > } > >