Skip to content

Commit

Permalink
mic: vop: Fix use-after-free on remove
Browse files Browse the repository at this point in the history
KASAN detects a use-after-free when vop devices are removed.

This problem was introduced by commit 0063e8b ("virtio_vop:
don't kfree device on register failure").  That patch moved the freeing
of the struct _vop_vdev to the release function, but failed to ensure
that vop holds a reference to the device when it doesn't want it to go
away.  A kfree() was replaced with a put_device() in the unregistration
path, but the last reference to the device is already dropped in
unregister_virtio_device() so the struct is freed before vop is done
with it.

Fix it by holding a reference until cleanup is done.  This is similar to
the fix in virtio_pci in commit 2989be0 ("virtio_pci: fix use
after free on release").

 ==================================================================
 BUG: KASAN: use-after-free in vop_scan_devices+0xc6c/0xe50 [vop]
 Read of size 8 at addr ffff88800da18580 by task kworker/0:1/12

 CPU: 0 PID: 12 Comm: kworker/0:1 Not tainted 5.0.0-rc4+ hardkernel#53
 Workqueue: events vop_hotplug_devices [vop]
 Call Trace:
  dump_stack+0x74/0xbb
  print_address_description+0x5d/0x2b0
  ? vop_scan_devices+0xc6c/0xe50 [vop]
  kasan_report+0x152/0x1aa
  ? vop_scan_devices+0xc6c/0xe50 [vop]
  ? vop_scan_devices+0xc6c/0xe50 [vop]
  vop_scan_devices+0xc6c/0xe50 [vop]
  ? vop_loopback_free_irq+0x160/0x160 [vop_loopback]
  process_one_work+0x7c0/0x14b0
  ? pwq_dec_nr_in_flight+0x2d0/0x2d0
  ? do_raw_spin_lock+0x120/0x280
  worker_thread+0x8f/0xbf0
  ? __kthread_parkme+0x78/0xf0
  ? process_one_work+0x14b0/0x14b0
  kthread+0x2ae/0x3a0
  ? kthread_park+0x120/0x120
  ret_from_fork+0x3a/0x50

 Allocated by task 12:
  kmem_cache_alloc_trace+0x13a/0x2a0
  vop_scan_devices+0x473/0xe50 [vop]
  process_one_work+0x7c0/0x14b0
  worker_thread+0x8f/0xbf0
  kthread+0x2ae/0x3a0
  ret_from_fork+0x3a/0x50

 Freed by task 12:
  kfree+0x104/0x310
  device_release+0x73/0x1d0
  kobject_put+0x14f/0x420
  unregister_virtio_device+0x32/0x50
  vop_scan_devices+0x19d/0xe50 [vop]
  process_one_work+0x7c0/0x14b0
  worker_thread+0x8f/0xbf0
  kthread+0x2ae/0x3a0
  ret_from_fork+0x3a/0x50

 The buggy address belongs to the object at ffff88800da18008
  which belongs to the cache kmalloc-2k of size 2048
 The buggy address is located 1400 bytes inside of
  2048-byte region [ffff88800da18008, ffff88800da18808)
 The buggy address belongs to the page:
 page:ffffea0000368600 count:1 mapcount:0 mapping:ffff88801440dbc0 index:0x0 compound_mapcount: 0
 flags: 0x4000000000010200(slab|head)
 raw: 4000000000010200 ffffea0000378608 ffffea000037a008 ffff88801440dbc0
 raw: 0000000000000000 00000000000d000d 00000001ffffffff 0000000000000000
 page dumped because: kasan: bad access detected

 Memory state around the buggy address:
  ffff88800da18480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff88800da18500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 >ffff88800da18580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                    ^
  ffff88800da18600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
  ffff88800da18680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ==================================================================

Fixes: 0063e8b ("virtio_vop: don't kfree device on register failure")
Signed-off-by: Vincent Whitchurch <[email protected]>
Cc: stable <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
vwax authored and gregkh committed Feb 1, 2019
1 parent 5b9633a commit 70ed714
Showing 1 changed file with 3 additions and 1 deletion.
4 changes: 3 additions & 1 deletion drivers/misc/mic/vop/vop_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,8 @@ static int _vop_remove_device(struct mic_device_desc __iomem *d,
int ret = -1;

if (ioread8(&dc->config_change) == MIC_VIRTIO_PARAM_DEV_REMOVE) {
struct device *dev = get_device(&vdev->vdev.dev);

dev_dbg(&vpdev->dev,
"%s %d config_change %d type %d vdev %p\n",
__func__, __LINE__,
Expand All @@ -600,7 +602,7 @@ static int _vop_remove_device(struct mic_device_desc __iomem *d,
iowrite8(-1, &dc->h2c_vdev_db);
if (status & VIRTIO_CONFIG_S_DRIVER_OK)
wait_for_completion(&vdev->reset_done);
put_device(&vdev->vdev.dev);
put_device(dev);
iowrite8(1, &dc->guest_ack);
dev_dbg(&vpdev->dev, "%s %d guest_ack %d\n",
__func__, __LINE__, ioread8(&dc->guest_ack));
Expand Down

0 comments on commit 70ed714

Please sign in to comment.