commit 246aaf60bd934b7571944b98a31078d519d637c6 Author: Juergen Gross Date: Wed May 3 15:57:18 2017 +0200 xen/blkback: don't free be structure too early The be structure must nor be freed when freeing the blkif structure isn't done. Otherwise a use-after-free of be when unmapping the ring used for communicating with the frontend will occur in case of a late call of xenblk_disconnect() (e.g. due to an I/O still active when trying to disconnect). diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 411d2ded2456..0614fb294e2b 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -33,6 +33,7 @@ struct backend_info { unsigned major; unsigned minor; char *mode; + int delayed; }; static struct kmem_cache *xen_blkif_cachep; @@ -262,8 +263,11 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif) * don't have any discard_io or other_io requests. So, checking * for inflight IO is enough. */ - if (atomic_read(&ring->inflight) > 0) + if (atomic_read(&ring->inflight) > 0) { + pr_warn("xen_blkif_disconnect: busy\n"); + blkif->be->delayed = 1; return -EBUSY; + } if (ring->irq) { unbind_from_irqhandler(ring->irq, ring); @@ -315,9 +319,11 @@ static int xen_blkif_disconnect(struct xen_blkif *blkif) static void xen_blkif_free(struct xen_blkif *blkif) { - - xen_blkif_disconnect(blkif); + pr_warn("xen_blkif_free: delayed = %d\n", blkif->be->delayed); + WARN_ON(xen_blkif_disconnect(blkif)); xen_vbd_free(&blkif->vbd); + kfree(blkif->be->mode); + kfree(blkif->be); /* Make sure everything is drained before shutting down */ kmem_cache_free(xen_blkif_cachep, blkif); @@ -512,8 +518,7 @@ static int xen_blkbk_remove(struct xenbus_device *dev) /* Put the reference we set in xen_blkif_alloc(). */ xen_blkif_put(be->blkif); - kfree(be->mode); - kfree(be); + return 0; }