[Stable-11.0.4 049/120] libvhost-user: protect against OOB vring queue access
Michael Tokarev <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu.stable,gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
From: "Michael S. Tsirkin" <[email protected]> SET_VRING_NUM, SET_VRING_ADDR, SET_VRING_BASE, and GET_VRING_BASE handlers all use the queue index from the message to access dev->vq[] without checking that it is below dev->max_queues, so a malformed message causes an out-of-bounds heap access. Frontend is trusted so not a security problem, but an OOB access is not a nice way to handle errors. Check, and panic. Fixes: 7b2e5c65f4 ("contrib: add libvhost-user") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3741 Cc: Stefano Garzarella <[email protected]> Reported-by: xlabai <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]> Message-ID: <dbba777b25f86587c8d131891a2b4b2be97e5c5b.1784899069.git.mst@redhat.com> (cherry picked from commit 758ef96a2dba157e930af7709f327435a153f7a3) Signed-off-by: Michael Tokarev <[email protected]> diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index bdaa6917f19..82e16c2c969 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -1200,6 +1200,12 @@ vu_set_vring_num_exec(VuDev *dev, VhostUserMsg *vmsg) DPRINT("State.index: %u\n", index); DPRINT("State.num: %u\n", num); + + if (index >= dev->max_queues) { + vu_panic(dev, "Invalid vring_num index: %u", index); + return false; + } + dev->vq[index].vring.num = num; return false; @@ -1210,7 +1216,7 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg) { struct vhost_vring_addr addr = vmsg->payload.addr, *vra = &addr; unsigned int index = vra->index; - VuVirtq *vq = &dev->vq[index]; + VuVirtq *vq; DPRINT("vhost_vring_addr:\n"); DPRINT(" index: %d\n", vra->index); @@ -1220,6 +1226,12 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg) DPRINT(" avail_user_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->avail_user_addr); DPRINT(" log_guest_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->log_guest_addr); + if (index >= dev->max_queues) { + vu_panic(dev, "Invalid vring_addr index: %u", index); + return false; + } + + vq = &dev->vq[index]; vq->vra = *vra; vq->vring.flags = vra->flags; vq->vring.log_guest_addr = vra->log_guest_addr; @@ -1256,6 +1268,12 @@ vu_set_vring_base_exec(VuDev *dev, VhostUserMsg *vmsg) DPRINT("State.index: %u\n", index); DPRINT("State.num: %u\n", num); + + if (index >= dev->max_queues) { + vu_panic(dev, "Invalid vring_base index: %u", index); + return false; + } + dev->vq[index].shadow_avail_idx = dev->vq[index].last_avail_idx = num; return false; @@ -1267,6 +1285,14 @@ vu_get_vring_base_exec(VuDev *dev, VhostUserMsg *vmsg) unsigned int index = vmsg->payload.state.index; DPRINT("State.index: %u\n", index); + + if (index >= dev->max_queues) { + vu_panic(dev, "Invalid vring_base index: %u", index); + vmsg->payload.state.num = 0; + vmsg->size = sizeof(vmsg->payload.state); + return true; + } + vmsg->payload.state.num = dev->vq[index].last_avail_idx; vmsg->size = sizeof(vmsg->payload.state); -- 2.47.3