@samitouri / QOSamiQemu / commits / fbdfdbb992

libvhost-user: protect against OOB writes in vu_set_inflight_fd

vu_set_inflight_fd() trusts the num_queues value from the VHOST_USER_SET_INFLIGHT_FD message without checking it against dev->max_queues, so an oversized value causes out-of-bounds writes to dev->vq. Front end is generally trusted so not a security problem, but OOB isn't a nice way to handle frontend bugs. Let's harden this a bit: check num_queues and panic if it's invalid. Fixes: 5f9ff1eff3 ("libvhost-user: Support tracking inflight I/O in shared memory") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3740 Cc: Stefano Garzarella <sgarzare@redhat.com> Reported-by: xlabai <xlabai@tencent.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <23b3f12388c1035f208550df9de9944c22d8d534.1784899127.git.mst@redhat.com>

Michael S. Tsirkin committed Jul 8, 2026 at 11:33 UTC fbdfdbb9920cb69408d53cb86a8e079a2054581e
1 file changed +20
subprojects/libvhost-user/libvhost-user.c
+20
@@ -1998,6 +1998,8 @@ vu_get_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
1998
1999 if (vmsg->size != sizeof(vmsg->payload.inflight)) {
2000 vu_panic(dev, "Invalid get_inflight_fd message:%d", vmsg->size);
2001 + vmsg_close_fds(vmsg);
2002 + vmsg->fd_num = 0;
2003 vmsg->payload.inflight.mmap_size = 0;
2004 return true;
2005 }
@@ -2005,6 +2007,15 @@ vu_get_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
2007 num_queues = vmsg->payload.inflight.num_queues;
2008 queue_size = vmsg->payload.inflight.queue_size;
2009
2010 + if (num_queues > dev->max_queues) {
2011 + vu_panic(dev, "Invalid get_inflight_fd num_queues: %"PRId16,
2012 + num_queues);
2013 + vmsg_close_fds(vmsg);
2014 + vmsg->fd_num = 0;
2015 + vmsg->payload.inflight.mmap_size = 0;
2016 + return true;
2017 + }
2018 +
2019 DPRINT("set_inflight_fd num_queues: %"PRId16"\n", num_queues);
2020 DPRINT("set_inflight_fd queue_size: %"PRId16"\n", queue_size);
2021
@@ -2052,6 +2063,7 @@ vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
2063 vmsg->size != sizeof(vmsg->payload.inflight)) {
2064 vu_panic(dev, "Invalid set_inflight_fd message size:%d fds:%d",
2065 vmsg->size, vmsg->fd_num);
2066 + vmsg_close_fds(vmsg);
2067 return false;
2068 }
2069
@@ -2061,6 +2073,13 @@ vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
2073 num_queues = vmsg->payload.inflight.num_queues;
2074 queue_size = vmsg->payload.inflight.queue_size;
2075
2076 + if (num_queues > dev->max_queues) {
2077 + vu_panic(dev, "Invalid set_inflight_fd num_queues: %"PRId16,
2078 + num_queues);
2079 + close(fd);
2080 + return false;
2081 + }
2082 +
2083 DPRINT("set_inflight_fd mmap_size: %"PRId64"\n", mmap_size);
2084 DPRINT("set_inflight_fd mmap_offset: %"PRId64"\n", mmap_offset);
2085 DPRINT("set_inflight_fd num_queues: %"PRId16"\n", num_queues);
@@ -2071,6 +2090,7 @@ vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
2090
2091 if (rc == MAP_FAILED) {
2092 vu_panic(dev, "set_inflight_fd mmap error: %s", strerror(errno));
2093 + close(fd);
2094 return false;
2095 }
2096