On Thu 01-02-18 19:58:45, Eric Biggers wrote:
> On Thu, Jan 11, 2018 at 06:00:08PM +0100, Jan Kara wrote:
> > On Thu 11-01-18 19:22:39, Hou Tao wrote:
> > > Hi,
> > >
> > > On 2018/1/11 16:24, Dan Carpenter wrote:
> > > > Thanks for your report and the patch. I am sending it to the
> > > > linux-block devs since it's already public.
> > > >
> > > > regards,
> > > > dan carpenter
> > >
> > > The User-after-free problem is not specific for loop device, it can also
> > > be reproduced on scsi device, and there are more race problems caused by
> > > the race between bdev open and gendisk shutdown [1].
> > >
> > > The cause of the UAF problem is that there are two instances of gendisk
> > > which share
> > > the same bdev. After the process owning the new gendisk increases
> > > bdev->bd_openers,
> > > the other process which owns the older gendisk will find bdev->bd_openers
> > > is not zero
> > > and will put the last reference of the older gendisk and cause
> > > User-after-free.
> > >
> > > I had proposed a patch for the problem, but it's still an incomplete fix
> > > for the race
> > > between gendisk shutdown and bdev opening.
> > >
> > > diff --git a/fs/block_dev.c b/fs/block_dev.c
> > > index 4a181fc..5ecdb9f 100644
> > > --- a/fs/block_dev.c
> > > +++ b/fs/block_dev.c
> > > @@ -1510,6 +1510,11 @@ static int __blkdev_get(struct block_device *bdev,
> > > fmode_t mode, int for_part)
> > > if (bdev->bd_bdi == &noop_backing_dev_info)
> > > bdev->bd_bdi =
> > > bdi_get(disk->queue->backing_dev_info);
> > > } else {
> > > + if (bdev->bd_disk != disk) {
> > > + ret = -ENXIO;
> > > + goto out_unlock_bdev;
> > > + }
> > > +
> > > if (bdev->bd_contains == bdev) {
> > > ret = 0;
> > > if (bdev->bd_disk->fops->open)
> > >
> > >
> > > As far as I know, Jan Kara is working on these problems. So, Jan, any
> > > suggestions ?
> >
> > Yeah, thanks for the ping. I was working today to get this fixed. I have
> > about 6 patches (attached) which should fix all the outstanding issues I'm
> > aware of. So far they are only boot tested. I will give them more
> > stress-testing next week and then post them officially but if you have time,
> > feel free to try them out as well. Thanks!
> >
>
> Jan, are you still planning to fix this? This was also reported by syzbot
> here:
> https://groups.google.com/d/msg/syzkaller-bugs/9wXx4YULITQ/0SK8vqxhAgAJ. Note
> that the C reproducer attached to that report doesn't work for me anymore
> following ae6650163c6 ("loop: fix concurrent lo_open/lo_release"). However,
> syzbot has still hit this on more recent kernels. Here's a C reproducer that
> still works for me on Linus' tree as of today, though it can take 5-10
> seconds:
Yes, I do plan to post the patches. I was just struggling with getting the
original failure reproduced (plus I had quite some other work, vacation) so
I couldn't really test whether my patches fix the reported problem. So
thanks for your reproducer, I'll try it out and see whether my patches fix
the problem.
Honza
> #include <fcntl.h>
> #include <linux/loop.h>
> #include <sys/ioctl.h>
> #include <unistd.h>
>
> int main()
> {
> int fd = open("/dev/loop-control", 0);
>
> if (!fork()) {
> for (;;)
> ioctl(fd, LOOP_CTL_ADD, 0);
> }
>
> if (!fork()) {
> for (;;)
> ioctl(fd, LOOP_CTL_REMOVE, 0);
> }
>
> fork();
> for (;;) {
> fd = open("/dev/loop0", O_EXCL);
> close(fd);
> }
> }
>
> This is the KASAN splat I get from the above:
>
> BUG: KASAN: use-after-free in disk_unblock_events+0x3e/0x40 block/genhd.c:1672
> Read of size 8 at addr ffff880030743670 by task systemd-udevd/165
>
> CPU: 1 PID: 165 Comm: systemd-udevd Not tainted 4.15.0-08279-gfe53d1443a146
> #38
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
> 1.11.0-20171110_100015-anatol 04/01/2014
> Call Trace:
> __dump_stack lib/dump_stack.c:17 [inline]
> dump_stack+0xb3/0x145 lib/dump_stack.c:53
> perf: interrupt took too long (7334 > 4816), lowering
> kernel.perf_event_max_sample_rate to 27000
> print_address_description+0x73/0x290 mm/kasan/report.c:252
> kasan_report_error mm/kasan/report.c:351 [inline]
> kasan_report+0x235/0x350 mm/kasan/report.c:409
> disk_unblock_events+0x3e/0x40 block/genhd.c:1672
> __blkdev_get+0x41b/0xd30 fs/block_dev.c:1535
> blkdev_get+0x283/0x980 fs/block_dev.c:1591
> do_dentry_open.isra.1+0x6c0/0xaf0 fs/open.c:752
> do_last fs/namei.c:3378 [inline]
> path_openat+0x587/0x28b0 fs/namei.c:3518
> do_filp_open+0x231/0x3a0 fs/namei.c:3553
> do_sys_open+0x399/0x610 fs/open.c:1059
> do_syscall_64+0x213/0x740 arch/x86/entry/common.c:285
> entry_SYSCALL64_slow_path+0x25/0x25
> RIP: 0033:0x7f51d23262ce
> RSP: 002b:00007ffdf1844310 EFLAGS: 00000246 ORIG_RAX: 0000000000000101
> RAX: ffffffffffffffda RBX: 0000562878961d30 RCX: 00007f51d23262ce
> RDX: 00000000000a0800 RSI: 0000562878974860 RDI: ffffffffffffff9c
> RBP: 0000562878965150 R08: 00007f51d1c9d914 R09: ffffffffffffffb0
> R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000000e
> R13: 0000562878965150 R14: 0000000000000004 R15: 0000000000000003
>
> Allocated by task 160:
> kmem_cache_alloc_node_trace include/linux/slab.h:413 [inline]
> kmalloc_node include/linux/slab.h:537 [inline]
> kzalloc_node include/linux/slab.h:699 [inline]
> __alloc_disk_node+0xb6/0x450 block/genhd.c:1415
> loop_add+0x3fd/0x9e0 drivers/block/loop.c:1814
> loop_probe+0x152/0x180 drivers/block/loop.c:1921
> kobj_lookup+0x176/0x310 drivers/base/map.c:124
> get_gendisk+0x28/0x290 block/genhd.c:804
> __blkdev_get+0x2ec/0xd30 fs/block_dev.c:1433
> blkdev_get+0x485/0x980 fs/block_dev.c:1591
> do_dentry_open.isra.1+0x6c0/0xaf0 fs/open.c:752
> do_last fs/namei.c:3378 [inline]
> path_openat+0x587/0x28b0 fs/namei.c:3518
> do_filp_open+0x231/0x3a0 fs/namei.c:3553
> do_sys_open+0x399/0x610 fs/open.c:1059
> entry_SYSCALL_64_fastpath+0x1e/0x8b
>
> Freed by task 165:
> __cache_free mm/slab.c:3484 [inline]
> kfree+0x8a/0xd0 mm/slab.c:3799
> disk_release+0x2c3/0x380 block/genhd.c:1264
> device_release+0x6e/0x1d0 drivers/base/core.c:811
> kobject_cleanup lib/kobject.c:646 [inline]
> kobject_release lib/kobject.c:675 [inline]
> kref_put include/linux/kref.h:70 [inline]
> kobject_put+0x14c/0x400 lib/kobject.c:692
> __blkdev_get+0x39f/0xd30 fs/block_dev.c:1528
> blkdev_get+0x283/0x980 fs/block_dev.c:1591
> do_dentry_open.isra.1+0x6c0/0xaf0 fs/open.c:752
> do_last fs/namei.c:3378 [inline]
> path_openat+0x587/0x28b0 fs/namei.c:3518
> do_filp_open+0x231/0x3a0 fs/namei.c:3553
> do_sys_open+0x399/0x610 fs/open.c:1059
> do_syscall_64+0x213/0x740 arch/x86/entry/common.c:285
> return_from_SYSCALL_64+0x0/0x75
>
> The buggy address belongs to the object at ffff880030743280
> which belongs to the cache kmalloc-2048 of size 2048
> The buggy address is located 1008 bytes inside of
> 2048-byte region [ffff880030743280, ffff880030743a80)
> The buggy address belongs to the page:
> page:ffffea0000a99670 count:1 mapcount:0 mapping:ffff880030742180 index:0x0
> compound_mapcount: 0
> flags: 0x100000000008100(slab|head)
> raw: 0100000000008100 ffff880030742180 0000000000000000 0000000100000003
> raw: ffffea0000b895a0 ffffea0000b91720 ffff880036000800
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff880030743500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff880030743580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> >ffff880030743600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff880030743680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff880030743700: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
--
Jan Kara <[email protected]>
SUSE Labs, CR