summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Hajnoczi2022-11-21 22:19:23 +0100
committerStefan Hajnoczi2022-11-30 00:15:26 +0100
commit7103895123d580bbe93e341241d200e75d8996a1 (patch)
treee805b02834ad199f47a6b4f61a7fbc8427819793
parenthw/display/qxl: Assert memory slot fits in preallocated MemoryRegion (diff)
downloadqemu-7103895123d580bbe93e341241d200e75d8996a1.tar.gz
qemu-7103895123d580bbe93e341241d200e75d8996a1.tar.xz
qemu-7103895123d580bbe93e341241d200e75d8996a1.zip
block-backend: avoid bdrv_unregister_buf() NULL pointer deref
bdrv_*() APIs expect a valid BlockDriverState. Calling them with bs=NULL leads to undefined behavior. Jonathan Cameron reported this following NULL pointer dereference when a VM with a virtio-blk device and a memory-backend-file object is terminated: 1. qemu_cleanup() closes all drives, setting blk->root to NULL 2. qemu_cleanup() calls user_creatable_cleanup(), which results in a RAM block notifier callback because the memory-backend-file is destroyed. 3. blk_unregister_buf() is called by virtio-blk's BlockRamRegistrar notifier callback and undefined behavior occurs. Fixes: baf422684d73 ("virtio-blk: use BDRV_REQ_REGISTERED_BUF optimization hint") Co-authored-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20221121211923.1993171-1-stefanha@redhat.com>
-rw-r--r--block/block-backend.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/block/block-backend.c b/block/block-backend.c
index b48c91f4e1..d98a96ff37 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -2576,14 +2576,25 @@ static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter)
bool blk_register_buf(BlockBackend *blk, void *host, size_t size, Error **errp)
{
+ BlockDriverState *bs = blk_bs(blk);
+
GLOBAL_STATE_CODE();
- return bdrv_register_buf(blk_bs(blk), host, size, errp);
+
+ if (bs) {
+ return bdrv_register_buf(bs, host, size, errp);
+ }
+ return true;
}
void blk_unregister_buf(BlockBackend *blk, void *host, size_t size)
{
+ BlockDriverState *bs = blk_bs(blk);
+
GLOBAL_STATE_CODE();
- bdrv_unregister_buf(blk_bs(blk), host, size);
+
+ if (bs) {
+ bdrv_unregister_buf(bs, host, size);
+ }
}
int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,