Skip to content
  • Ryan Harper's avatar
    Do not delete BlockDriverState when deleting the drive · d22b2f41
    Ryan Harper authored
    
    
    When removing a drive from the host-side via drive_del we currently have
    the following path:
    
    drive_del
    qemu_aio_flush()
    bdrv_close()    // zaps bs->drv, which makes any subsequent I/O get
                    // dropped.  Works as designed
    drive_uninit()
    bdrv_delete()   // frees the bs.  Since the device is still connected to
                    // bs, any subsequent I/O is a use-after-free.
    
    The value of bs->drv becomes unpredictable on free.  As long as it
    remains null, I/O still gets dropped, however it could become non-null
    at any point after the free resulting SEGVs or other QEMU state
    corruption.
    
    To resolve this issue as simply as possible, we can chose to not
    actually delete the BlockDriverState pointer.  Since bdrv_close()
    handles setting the drv pointer to NULL, we just need to remove the
    BlockDriverState from the QLIST that is used to enumerate the block
    devices.  This is currently handled within bdrv_delete, so move this
    into its own function, bdrv_make_anon().
    
    The result is that we can now invoke drive_del, this closes the file
    descriptors and sets BlockDriverState->drv to NULL which prevents futher
    IO to the device, and since we do not free BlockDriverState, we don't
    have to worry about the copy retained in the block devices.
    
    We also don't attempt to remove the qdev property since we are no longer
    deleting the BlockDriverState on drives with associated drives.  This
    also allows for removing Drives with no devices associated either.
    
    Reported-by: default avatarMarkus Armbruster <armbru@redhat.com>
    Signed-off-by: default avatarRyan Harper <ryanh@us.ibm.com>
    Acked-by: default avatarMarkus Armbruster <armbru@redhat.com>
    Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
    d22b2f41