[PATCH] vhost-user: check memory slot availability for SHMEM_MAP

Feifan Qian posted 1 patch 5 days, 5 hours ago
Failed in applying to current master (apply log)
hw/virtio/vhost-user.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
[PATCH] vhost-user: check memory slot availability for SHMEM_MAP
Posted by Feifan Qian 5 days, 5 hours ago
SHMEM_MAP creates a separate RAM MemoryRegion for every mapping. It can
therefore make a vhost-user memory table exceed the number of slots
negotiated with the backend. The region reconciliation code then indexes
fixed-size bookkeeping arrays past their end.

Reject a mapping before changing the memory topology if KVM or a vhost
backend has no unreserved slot left. Also validate each memory table
against the negotiated vhost-user limit as a final defense for mappings
that become visible in a later memory transaction.

Fixes: b52e1896e764 ("vhost-user: Add VirtIO Shared Memory map request")
Signed-off-by: Feifan Qian <bea1e@proton.me>
---
Tested with an ASan/UBSan x86_64 build and a vhost-user backend that
mapped one-page SHMEM regions up to the 512-slot limit. The next
SHMEM_MAP request was rejected and QEMU remained alive. Before this
patch, the same reproducer reported an out-of-bounds write at found[512]
in scrub_shadow_regions(). qtest-x86_64/qos-test also passed all 140
subtests.

hw/virtio/vhost-user.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 517cc4ca71..7f141c116b 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -10,6 +10,7 @@

#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "hw/mem/memory-device.h"
#include "hw/virtio/virtio-dmabuf.h"
#include "hw/virtio/virtio-qmp.h"
#include "hw/virtio/vhost.h"
@@ -1123,6 +1124,13 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
dev, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS);
int ret;

+ if (mem->nregions > u->user->memory_slots) {
+ error_report("vhost-user memory table has %u regions, "
+ "but the backend supports only %d",
+ mem->nregions, u->user->memory_slots);
+ return -ENOSPC;
+ }
+
if (do_postcopy) {
/*
* Postcopy has enough differences that it's best done in it's own
@@ -1937,6 +1945,7 @@ vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
VhostUserMMap *vu_mmap = &payload->mmap;
VirtioSharedMemoryMapping *existing;
Error *local_err = NULL;
+ unsigned int reserved_memslots;
int ret = 0;

if (fd < 0) {
@@ -1977,6 +1986,15 @@ vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
}
}

+ reserved_memslots = memory_devices_get_reserved_memslots();
+ if ((kvm_enabled() &&
+ kvm_get_free_memslots() <= reserved_memslots) ||
+ vhost_get_free_memslots() <= reserved_memslots) {
+ error_report("No free memory slots for shared memory mapping");
+ ret = -ENOSPC;
+ goto send_reply;
+ }
+
memory_region_transaction_begin();

/* Create VirtioSharedMemoryMapping object */
--2.43.0