Skip to content
Snippets Groups Projects
  • Stefan Hajnoczi's avatar
    1e3552db
    block-backend: prevent dangling BDS pointers across aio_poll() · 1e3552db
    Stefan Hajnoczi authored
    The BlockBackend root child can change when aio_poll() is invoked. This
    happens when a temporary filter node is removed upon blockjob
    completion, for example.
    
    Functions in block/block-backend.c must be aware of this when using a
    blk_bs() pointer across aio_poll() because the BlockDriverState refcnt
    may reach 0, resulting in a stale pointer.
    
    One example is scsi_device_purge_requests(), which calls blk_drain() to
    wait for in-flight requests to cancel. If the backup blockjob is active,
    then the BlockBackend root child is a temporary filter BDS owned by the
    blockjob. The blockjob can complete during bdrv_drained_begin() and the
    last reference to the BDS is released when the temporary filter node is
    removed. This results in a use-after-free when blk_drain() calls
    bdrv_drained_end(bs) on the dangling pointer.
    
    Explicitly hold a reference to bs across block APIs that invoke
    aio_poll().
    
    Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2021778
    Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2036178
    
    
    Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
    Message-Id: <20220111153613.25453-2-stefanha@redhat.com>
    Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
    1e3552db
    History
    block-backend: prevent dangling BDS pointers across aio_poll()
    Stefan Hajnoczi authored
    The BlockBackend root child can change when aio_poll() is invoked. This
    happens when a temporary filter node is removed upon blockjob
    completion, for example.
    
    Functions in block/block-backend.c must be aware of this when using a
    blk_bs() pointer across aio_poll() because the BlockDriverState refcnt
    may reach 0, resulting in a stale pointer.
    
    One example is scsi_device_purge_requests(), which calls blk_drain() to
    wait for in-flight requests to cancel. If the backup blockjob is active,
    then the BlockBackend root child is a temporary filter BDS owned by the
    blockjob. The blockjob can complete during bdrv_drained_begin() and the
    last reference to the BDS is released when the temporary filter node is
    removed. This results in a use-after-free when blk_drain() calls
    bdrv_drained_end(bs) on the dangling pointer.
    
    Explicitly hold a reference to bs across block APIs that invoke
    aio_poll().
    
    Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2021778
    Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2036178
    
    
    Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
    Message-Id: <20220111153613.25453-2-stefanha@redhat.com>
    Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
block-backend.c 64.71 KiB