]>
Commit | Line | Data |
---|---|---|
5876fb65 WB |
1 | From a8ceb006190b9072b0b9866ec5a07bd6de4eca6d Mon Sep 17 00:00:00 2001 |
2 | From: Prasad J Pandit <pjp@fedoraproject.org> | |
3 | Date: Tue, 6 Sep 2016 23:23:17 +0530 | |
4 | Subject: [PATCH 5/6] scsi: pvscsi: avoid infinite loop while building SG list | |
5 | ||
6 | In PVSCSI paravirtual SCSI bus, pvscsi_convert_sglist can take a very | |
7 | long time or go into an infinite loop due to two different bugs: | |
8 | ||
9 | 1) the request descriptor data length is defined to be 64 bit. While | |
10 | building SG list from a request descriptor, it gets truncated to 32bit | |
11 | in routine 'pvscsi_convert_sglist'. This could lead to an infinite loop | |
12 | situation for large 'dataLen' values, when data_length is cast to uint32_t | |
13 | and chunk_size becomes always zero. Fix this by removing the incorrect | |
14 | cast. | |
15 | ||
16 | 2) pvscsi_get_next_sg_elem can be called arbitrarily many times if the | |
17 | element has a zero length. Get out of the loop early when this happens, | |
18 | by introducing an upper limit on the number of SG list elements. | |
19 | ||
20 | Reported-by: Li Qiang <liqiang6-s@360.cn> | |
21 | Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> | |
22 | --- | |
23 | hw/scsi/vmw_pvscsi.c | 11 ++++++----- | |
24 | 1 file changed, 6 insertions(+), 5 deletions(-) | |
25 | ||
26 | diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c | |
27 | index 22f872c..e43e0a4 100644 | |
28 | --- a/hw/scsi/vmw_pvscsi.c | |
29 | +++ b/hw/scsi/vmw_pvscsi.c | |
30 | @@ -40,6 +40,8 @@ | |
31 | #define PVSCSI_MAX_DEVS (64) | |
32 | #define PVSCSI_MSIX_NUM_VECTORS (1) | |
33 | ||
34 | +#define PVSCSI_MAX_SG_ELEM 2048 | |
35 | + | |
36 | #define PVSCSI_MAX_CMD_DATA_WORDS \ | |
37 | (sizeof(PVSCSICmdDescSetupRings)/sizeof(uint32_t)) | |
38 | ||
39 | @@ -629,17 +631,16 @@ pvscsi_queue_pending_descriptor(PVSCSIState *s, SCSIDevice **d, | |
40 | static void | |
41 | pvscsi_convert_sglist(PVSCSIRequest *r) | |
42 | { | |
43 | - int chunk_size; | |
44 | + uint32_t chunk_size, elmcnt = 0; | |
45 | uint64_t data_length = r->req.dataLen; | |
46 | PVSCSISGState sg = r->sg; | |
47 | - while (data_length) { | |
48 | - while (!sg.resid) { | |
49 | + while (data_length && elmcnt < PVSCSI_MAX_SG_ELEM) { | |
50 | + while (!sg.resid && elmcnt++ < PVSCSI_MAX_SG_ELEM) { | |
51 | pvscsi_get_next_sg_elem(&sg); | |
52 | trace_pvscsi_convert_sglist(r->req.context, r->sg.dataAddr, | |
53 | r->sg.resid); | |
54 | } | |
55 | - assert(data_length > 0); | |
56 | - chunk_size = MIN((unsigned) data_length, sg.resid); | |
57 | + chunk_size = MIN(data_length, sg.resid); | |
58 | if (chunk_size) { | |
59 | qemu_sglist_add(&r->sgl, sg.dataAddr, chunk_size); | |
60 | } | |
61 | -- | |
62 | 2.1.4 | |
63 |