vscsi_send_adapter_info() used the guest-supplied common.length field directly as the size argument to spapr_vio_dma_write(). Since common.length is controlled by the guest, a value larger than sizeof(struct mad_adapter_info_data) (148 bytes) caused dma_memory_write() to read past the end of the stack-allocated info struct, leaking arbitrary host stack contents into guest memory.
Fix this by clamping the write length to sizeof(info), then using spapr_vio_dma_set() to zero-fill any remaining bytes the guest requested beyond that size. This mirrors the existing pattern in vscsi_send_capabilities(). Closes: https://gitlab.com/qemu-project/qemu/-/work_items/4626 Reported-by: Guthrie McAfee Armstrong <[email protected]> Signed-off-by: Chinmay Rath <[email protected]> --- hw/scsi/spapr_vscsi.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index b4c8f94d22..7ec780da79 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -966,6 +966,8 @@ static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req) { struct viosrp_adapter_info *sinfo; struct mad_adapter_info_data info; + uint16_t len, req_len; + uint64_t buffer; int rc; sinfo = &req_iu(req)->mad.adapter_info; @@ -985,11 +987,23 @@ static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req) info.os_type = cpu_to_be32(2); info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9); - rc = spapr_vio_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer), - &info, be16_to_cpu(sinfo->common.length)); + req_len = len = be16_to_cpu(sinfo->common.length); + buffer = be64_to_cpu(sinfo->buffer); + if (len > sizeof(info)) { + fprintf(stderr, "vscsi_send_adapter_info: adapter info size mismatch !\n"); + /* + * Just read and populate the structure that is known. + * Zero rest of the structure. + */ + len = sizeof(info); + } + rc = spapr_vio_dma_write(&s->vdev, buffer, &info, len); if (rc) { fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n"); } + if (req_len > len) { + spapr_vio_dma_set(&s->vdev, (buffer + len), 0, (req_len - len)); + } sinfo->common.status = rc ? cpu_to_be32(1) : 0; -- 2.55.0
