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:
#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