Eric Biggers wrote: > But, there is still a related bug: when mounting sysfs, if register_shrinker() > fails in sget_userns(), then kernfs_kill_sb() gets called, which frees the > 'struct kernfs_super_info'. But, the 'struct kernfs_super_info' is also freed > in kernfs_mount_ns() by: > > sb = sget_userns(fs_type, kernfs_test_super, kernfs_set_super, flags, > &init_user_ns, info); > if (IS_ERR(sb) || sb->s_fs_info != info) > kfree(info); > if (IS_ERR(sb)) > return ERR_CAST(sb); > > I guess the problem is that sget_userns() shouldn't take ownership of the 'info' > if it returns an error -- but, it actually does if register_shrinker() fails, > resulting in a double free. > > Here is a reproducer and the KASAN splat. This is on Linus' tree (87ef12027b9b) > with vfs/for-linus merged in. I'm waiting for response from Michal Hocko regarding http://lkml.kernel.org/r/201804111909.EGC64586.QSFLFJFOVHOOtM@xxxxxxxxxxxxxxxxxxx . > > #define _GNU_SOURCE > #include <fcntl.h> > #include <sched.h> > #include <stdio.h> > #include <stdlib.h> > #include <sys/mount.h> > #include <sys/stat.h> > #include <unistd.h> > > int main() > { > int fd, i; > char buf[16]; > > unshare(CLONE_NEWNET); > system("echo N > /sys/kernel/debug/failslab/ignore-gfp-wait"); > system("echo 0 | tee /sys/kernel/debug/fail*/verbose"); > fd = open("/proc/thread-self/fail-nth", O_WRONLY); > for (i = 0; ; i++) { > write(fd, buf, sprintf(buf, "%d", i)); > mount("sysfs", "mnt", "sysfs", 0, NULL); > umount("mnt"); > } > }