@samitouri / QOSamiQemu / commits / 7997130293

virtio-scsi: pass the same cdb_size to virtio_scsi_pop_req and virtio_scsi_handle_cmd_req_prepare

Ensure that there is no allocation/usage mismatch when requests are processed in virtio_scsi_handle_cmd_vq. To do this, retrieve the value once and pass it to both functions. For other calls to virtio_scsi_pop_req the extra size can be 0, because control and event requests fit entirely in VirtIOSCSIReq. Reported-by: Jihe Wang <wangjihe.mail@gmail.com> Tested-by: Jihe Wang <wangjihe.mail@gmail.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Fixes: CVE-2026-5763 Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Paolo Bonzini committed Mar 27, 2026 at 22:00 UTC 79971302935472232a68073faddb085177e3ca54
1 file changed +15 -11
hw/scsi/virtio-scsi.c
+15 -11
@@ -227,16 +227,16 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
227 return 0;
228 }
229
230 -static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq, QemuMutex *vq_lock)
230 +static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq, size_t extra_req_size,
231 + QemuMutex *vq_lock)
232 {
232 - VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
233 VirtIOSCSIReq *req;
234
235 if (vq_lock) {
236 qemu_mutex_lock(vq_lock);
237 }
238
239 - req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size);
239 + req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + extra_req_size);
240
241 if (vq_lock) {
242 qemu_mutex_unlock(vq_lock);
@@ -682,7 +682,7 @@ static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
682 {
683 VirtIOSCSIReq *req;
684
685 - while ((req = virtio_scsi_pop_req(s, vq, &s->ctrl_lock))) {
685 + while ((req = virtio_scsi_pop_req(s, vq, 0, &s->ctrl_lock))) {
686 virtio_scsi_handle_ctrl_req(s, req);
687 }
688 }
@@ -850,13 +850,14 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
850 virtio_scsi_complete_cmd_req(req);
851 }
852
853 -static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
853 +static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req,
854 + size_t cdb_size)
855 {
856 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
857 SCSIDevice *d;
858 int rc;
859
859 - rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
860 + rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + cdb_size,
861 sizeof(VirtIOSCSICmdResp) + vs->sense_size);
862 if (rc < 0) {
863 if (rc == -ENOTSUP) {
@@ -878,7 +879,7 @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
879 }
880 req->sreq = scsi_req_new(d, req->req.cmd.tag,
881 virtio_scsi_get_lun(req->req.cmd.lun),
881 - req->req.cmd.cdb, vs->cdb_size, req);
882 + req->req.cmd.cdb, cdb_size, req);
883
884 if (req->sreq->cmd.mode != SCSI_XFER_NONE
885 && (req->sreq->cmd.mode != req->mode ||
@@ -913,12 +914,15 @@ static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
914 QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
915
916 do {
917 + VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
918 + size_t cdb_size = qatomic_read(&vs->cdb_size);
919 +
920 if (suppress_notifications) {
921 virtio_queue_set_notification(vq, 0);
922 }
923
920 - while ((req = virtio_scsi_pop_req(s, vq, NULL))) {
921 - ret = virtio_scsi_handle_cmd_req_prepare(s, req);
924 + while ((req = virtio_scsi_pop_req(s, vq, cdb_size, NULL))) {
925 + ret = virtio_scsi_handle_cmd_req_prepare(s, req, cdb_size);
926 if (!ret) {
927 QTAILQ_INSERT_TAIL(&reqs, req, next);
928 } else if (ret == -EINVAL) {
@@ -989,7 +993,7 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
993 }
994
995 vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size);
992 - vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
996 + qatomic_set(&vs->cdb_size, virtio_ldl_p(vdev, &scsiconf->cdb_size));
997 }
998
999 static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
@@ -1050,7 +1054,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s,
1054 return;
1055 }
1056
1053 - req = virtio_scsi_pop_req(s, vs->event_vq, &s->event_lock);
1057 + req = virtio_scsi_pop_req(s, vs->event_vq, 0, &s->event_lock);
1058 WITH_QEMU_LOCK_GUARD(&s->event_lock) {
1059 if (!req) {
1060 s->events_dropped = true;