summaryrefslogtreecommitdiffstats
path: root/subprojects/libvhost-user/libvhost-user.c
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/libvhost-user/libvhost-user.c')
-rw-r--r--subprojects/libvhost-user/libvhost-user.c86
1 files changed, 64 insertions, 22 deletions
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
index 787f4d2d4f..47d2efc60f 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -690,6 +690,29 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
VuDevRegion *dev_region = &dev->regions[dev->nregions];
void *mmap_addr;
+ if (vmsg->fd_num != 1) {
+ vmsg_close_fds(vmsg);
+ vu_panic(dev, "VHOST_USER_ADD_MEM_REG received %d fds - only 1 fd "
+ "should be sent for this message type", vmsg->fd_num);
+ return false;
+ }
+
+ if (vmsg->size < VHOST_USER_MEM_REG_SIZE) {
+ close(vmsg->fds[0]);
+ vu_panic(dev, "VHOST_USER_ADD_MEM_REG requires a message size of at "
+ "least %d bytes and only %d bytes were received",
+ VHOST_USER_MEM_REG_SIZE, vmsg->size);
+ return false;
+ }
+
+ if (dev->nregions == VHOST_USER_MAX_RAM_SLOTS) {
+ close(vmsg->fds[0]);
+ vu_panic(dev, "failing attempt to hot add memory via "
+ "VHOST_USER_ADD_MEM_REG message because the backend has "
+ "no free ram slots available");
+ return false;
+ }
+
/*
* If we are in postcopy mode and we receive a u64 payload with a 0 value
* we know all the postcopy client bases have been received, and we
@@ -728,12 +751,12 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
* accessing it before we userfault.
*/
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_NONE, MAP_SHARED,
+ PROT_NONE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[0], 0);
} else {
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_READ | PROT_WRITE, MAP_SHARED, vmsg->fds[0],
- 0);
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE,
+ vmsg->fds[0], 0);
}
if (mmap_addr == MAP_FAILED) {
@@ -796,10 +819,24 @@ static inline bool reg_equal(VuDevRegion *vudev_reg,
static bool
vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
- int i, j;
- bool found = false;
- VuDevRegion shadow_regions[VHOST_USER_MAX_RAM_SLOTS] = {};
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
+ int i;
+ bool found = false;
+
+ if (vmsg->fd_num != 1) {
+ vmsg_close_fds(vmsg);
+ vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - only 1 fd "
+ "should be sent for this message type", vmsg->fd_num);
+ return false;
+ }
+
+ if (vmsg->size < VHOST_USER_MEM_REG_SIZE) {
+ close(vmsg->fds[0]);
+ vu_panic(dev, "VHOST_USER_REM_MEM_REG requires a message size of at "
+ "least %d bytes and only %d bytes were received",
+ VHOST_USER_MEM_REG_SIZE, vmsg->size);
+ return false;
+ }
DPRINT("Removing region:\n");
DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n",
@@ -811,35 +848,40 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
DPRINT(" mmap_offset 0x%016"PRIx64"\n",
msg_region->mmap_offset);
- for (i = 0, j = 0; i < dev->nregions; i++) {
- if (!reg_equal(&dev->regions[i], msg_region)) {
- shadow_regions[j].gpa = dev->regions[i].gpa;
- shadow_regions[j].size = dev->regions[i].size;
- shadow_regions[j].qva = dev->regions[i].qva;
- shadow_regions[j].mmap_addr = dev->regions[i].mmap_addr;
- shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset;
- j++;
- } else {
- found = true;
+ for (i = 0; i < dev->nregions; i++) {
+ if (reg_equal(&dev->regions[i], msg_region)) {
VuDevRegion *r = &dev->regions[i];
void *m = (void *) (uintptr_t) r->mmap_addr;
if (m) {
munmap(m, r->size + r->mmap_offset);
}
+
+ /*
+ * Shift all affected entries by 1 to close the hole at index i and
+ * zero out the last entry.
+ */
+ memmove(dev->regions + i, dev->regions + i + 1,
+ sizeof(VuDevRegion) * (dev->nregions - i - 1));
+ memset(dev->regions + dev->nregions - 1, 0, sizeof(VuDevRegion));
+ DPRINT("Successfully removed a region\n");
+ dev->nregions--;
+ i--;
+
+ found = true;
+
+ /* Continue the search for eventual duplicates. */
}
}
if (found) {
- memcpy(dev->regions, shadow_regions,
- sizeof(VuDevRegion) * VHOST_USER_MAX_RAM_SLOTS);
- DPRINT("Successfully removed a region\n");
- dev->nregions--;
vmsg_set_reply_u64(vmsg, 0);
} else {
vu_panic(dev, "Specified region not found\n");
}
+ close(vmsg->fds[0]);
+
return true;
}
@@ -878,7 +920,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
* accessing it before we userfault
*/
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_NONE, MAP_SHARED,
+ PROT_NONE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[i], 0);
if (mmap_addr == MAP_FAILED) {
@@ -965,7 +1007,7 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)
* mapped address has to be page aligned, and we use huge
* pages. */
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
- PROT_READ | PROT_WRITE, MAP_SHARED,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[i], 0);
if (mmap_addr == MAP_FAILED) {