scsi-generic: fix buffer overflow on block limits inquiry

Using linux 6.x guest, at boot time, an inquiry on a scsi-generic
device makes qemu crash.  This is caused by a buffer overflow when
scsi-generic patches the block limits VPD page.

Do the operations on a temporary on-stack buffer that is guaranteed
to be large enough.

Reported-by: Théo Maillart <tmaillart@freebox.fr>
Analyzed-by: Théo Maillart <tmaillart@freebox.fr>
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2023-05-10 18:15:25 +02:00
parent c9214c9355
commit 9bd634b2f5

View File

@ -191,12 +191,16 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) && if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) &&
(r->req.cmd.buf[1] & 0x01)) { (r->req.cmd.buf[1] & 0x01)) {
page = r->req.cmd.buf[2]; page = r->req.cmd.buf[2];
if (page == 0xb0) { if (page == 0xb0 && r->buflen >= 8) {
uint8_t buf[16] = {};
uint8_t buf_used = MIN(r->buflen, 16);
uint64_t max_transfer = calculate_max_transfer(s); uint64_t max_transfer = calculate_max_transfer(s);
stl_be_p(&r->buf[8], max_transfer);
/* Also take care of the opt xfer len. */ memcpy(buf, r->buf, buf_used);
stl_be_p(&r->buf[12], stl_be_p(&buf[8], max_transfer);
MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer, ldl_be_p(&buf[12])));
memcpy(r->buf + 8, buf + 8, buf_used - 8);
} else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) { } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
/* /*
* Now we're capable of supplying the VPD Block Limits * Now we're capable of supplying the VPD Block Limits