diff options
author | Philippe Mathieu-Daudé | 2020-03-05 13:12:52 +0100 |
---|---|---|
committer | David Gibson | 2020-03-17 05:08:50 +0100 |
commit | 13a5490536c5c260ad158d5b9672daebcd1d85d5 (patch) | |
tree | e56917f15045a9356aa437d94d980ffb2bf2699e /hw/scsi/spapr_vscsi.c | |
parent | hw/scsi/spapr_vscsi: Do not mix SRP IU size with DMA buffer size (diff) | |
download | qemu-13a5490536c5c260ad158d5b9672daebcd1d85d5.tar.gz qemu-13a5490536c5c260ad158d5b9672daebcd1d85d5.tar.xz qemu-13a5490536c5c260ad158d5b9672daebcd1d85d5.zip |
hw/scsi/spapr_vscsi: Prevent buffer overflow
Depending on the length of sense data, vscsi_send_rsp() can
overrun the buffer size.
Do not copy more than SRP_MAX_IU_DATA_LEN bytes, and assert
that vscsi_send_iu() is always called with a size in range.
Reported-by: Paolo Bonzini <pbonzini@redhat.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20200305121253.19078-7-philmd@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw/scsi/spapr_vscsi.c')
-rw-r--r-- | hw/scsi/spapr_vscsi.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index acf9bb50bc..c4c4f31170 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -55,6 +55,8 @@ #define VSCSI_MAX_SECTORS 4096 #define VSCSI_REQ_LIMIT 24 +/* Maximum size of a IU payload */ +#define SRP_MAX_IU_DATA_LEN (SRP_MAX_IU_LEN - sizeof(union srp_iu)) #define SRP_RSP_SENSE_DATA_LEN 18 #define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL @@ -181,6 +183,8 @@ static int vscsi_send_iu(VSCSIState *s, vscsi_req *req, { long rc, rc1; + assert(length <= SRP_MAX_IU_LEN); + /* First copy the SRP */ rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr, &req->viosrp_iu_buf, length); @@ -266,10 +270,12 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, if (status) { iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2; if (req->senselen) { + int sense_data_len = MIN(req->senselen, SRP_MAX_IU_DATA_LEN); + iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; - iu->srp.rsp.sense_data_len = cpu_to_be32(req->senselen); - memcpy(iu->srp.rsp.data, req->sense, req->senselen); - total_len += req->senselen; + iu->srp.rsp.sense_data_len = cpu_to_be32(sense_data_len); + memcpy(iu->srp.rsp.data, req->sense, sense_data_len); + total_len += sense_data_len; } } else { iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1; @@ -896,6 +902,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req) } /* Compose the response here as */ + QEMU_BUILD_BUG_ON(SRP_MAX_IU_DATA_LEN < 4); memset(iu, 0, sizeof(struct srp_rsp) + 4); iu->srp.rsp.opcode = SRP_RSP; iu->srp.rsp.req_lim_delta = cpu_to_be32(1); |