aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorRaphael Norwitz <raphael.norwitz@nutanix.com>2020-07-17 04:21:30 +0000
committerMichael S. Tsirkin <mst@redhat.com>2020-07-27 10:28:28 -0400
commit4fdecf0543b49b8e171510104f3117538b9d1fe9 (patch)
tree2ed49bd06e74960fc9c79da17a3dec42c8cd7bc0 /hw
parent2ebc21216f58f6fcbf16f7ec0bebe7f72ab3d8ca (diff)
Fix vhost-user buffer over-read on ram hot-unplug
The VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS vhost-user protocol feature introduced a shadow-table, used by the backend to dynamically determine how a vdev's memory regions have changed since the last vhost_user_set_mem_table() call. On hot-remove, a memmove() operation is used to overwrite the removed shadow region descriptor(s). The size parameter of this memmove was off by 1 such that if a VM with a backend supporting the VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS filled it's shadow-table (by performing the maximum number of supported hot-add operatons) and attempted to remove the last region, Qemu would read an out of bounds value and potentially crash. This change fixes the memmove() bounds such that this erroneous read can never happen. Signed-off-by: Peter Turschmid <peter.turschm@nutanix.com> Signed-off-by: Raphael Norwitz <raphael.norwitz@nutanix.com> Message-Id: <1594799958-31356-1-git-send-email-raphael.norwitz@nutanix.com> Fixes: f1aeb14b0809 ("Transmit vhost-user memory regions individually") Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/virtio/vhost-user.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 31231218dc..d7e2423762 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -672,7 +672,7 @@ static int send_remove_regions(struct vhost_dev *dev,
memmove(&u->shadow_regions[shadow_reg_idx],
&u->shadow_regions[shadow_reg_idx + 1],
sizeof(struct vhost_memory_region) *
- (u->num_shadow_regions - shadow_reg_idx));
+ (u->num_shadow_regions - shadow_reg_idx - 1));
u->num_shadow_regions--;
}