Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] zfcp: Bounds checking for deferred error trace

The pl vector has scount elements, i.e. pl[scount-1] is the last valid
element. For maximum sized requests, payload->counter == scount after
the last loop iteration. Therefore, do bounds checking first (with
boolean shortcut) to not access the invalid element pl[scount].

Do not trust the maximum sbale->scount value from the HBA
but ensure we won't access the pl vector out of our allocated bounds.
While at it, clean up scoping and prevent unnecessary memset.

Minor fix for 86a9668a8d29ea711613e1cb37efa68e7c4db564
"[SCSI] zfcp: support for hardware data router"

Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
Reviewed-by: Martin Peschke <mpeschke@linux.vnet.ibm.com>
Cc: <stable@vger.kernel.org> #3.2+
Signed-off-by: James Bottomley <JBottomley@Parallels.com>

authored by

Steffen Maier and committed by
James Bottomley
01e60527 0100998d

+11 -7
+1 -1
drivers/s390/scsi/zfcp_dbf.c
··· 191 191 length = min((u16)sizeof(struct qdio_buffer), 192 192 (u16)ZFCP_DBF_PAY_MAX_REC); 193 193 194 - while ((char *)pl[payload->counter] && payload->counter < scount) { 194 + while (payload->counter < scount && (char *)pl[payload->counter]) { 195 195 memcpy(payload->data, (char *)pl[payload->counter], length); 196 196 debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length)); 197 197 payload->counter++;
+10 -6
drivers/s390/scsi/zfcp_qdio.c
··· 102 102 { 103 103 struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; 104 104 struct zfcp_adapter *adapter = qdio->adapter; 105 - struct qdio_buffer_element *sbale; 106 105 int sbal_no, sbal_idx; 107 - void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; 108 - u64 req_id; 109 - u8 scount; 110 106 111 107 if (unlikely(qdio_err)) { 112 - memset(pl, 0, ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); 113 108 if (zfcp_adapter_multi_buffer_active(adapter)) { 109 + void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; 110 + struct qdio_buffer_element *sbale; 111 + u64 req_id; 112 + u8 scount; 113 + 114 + memset(pl, 0, 115 + ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); 114 116 sbale = qdio->res_q[idx]->element; 115 117 req_id = (u64) sbale->addr; 116 - scount = sbale->scount + 1; /* incl. signaling SBAL */ 118 + scount = min(sbale->scount + 1, 119 + ZFCP_QDIO_MAX_SBALS_PER_REQ + 1); 120 + /* incl. signaling SBAL */ 117 121 118 122 for (sbal_no = 0; sbal_no < scount; sbal_no++) { 119 123 sbal_idx = (idx + sbal_no) %