aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2023-05-10 18:15:25 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2023-05-18 08:53:51 +0200
commit9bd634b2f5e2f10fe35d7609eb83f30583f2e15a (patch)
tree658e4afb04d3e529da16f8ba56160bf0b5709d3c /hw/scsi
parentc9214c935564775483ee4865857dbef1bd4a7ad9 (diff)
downloadqemu-9bd634b2f5e2f10fe35d7609eb83f30583f2e15a.zip
qemu-9bd634b2f5e2f10fe35d7609eb83f30583f2e15a.tar.gz
qemu-9bd634b2f5e2f10fe35d7609eb83f30583f2e15a.tar.bz2
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>
Diffstat (limited to 'hw/scsi')
-rw-r--r--hw/scsi/scsi-generic.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index ac9fa66..2417f0a 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -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) &&
(r->req.cmd.buf[1] & 0x01)) {
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);
- stl_be_p(&r->buf[8], max_transfer);
- /* Also take care of the opt xfer len. */
- stl_be_p(&r->buf[12],
- MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
+
+ memcpy(buf, r->buf, buf_used);
+ stl_be_p(&buf[8], max_transfer);
+ 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) {
/*
* Now we're capable of supplying the VPD Block Limits