Skip to content

Commit d994ac7

Browse files
Quinn Trangregkh
authored andcommitted
scsi: qla2xxx: Fix mem access after free
commit b843add upstream. System crash, where driver is accessing scsi layer's memory (scsi_cmnd->device->host) to search for a well known internal pointer (vha). The scsi_cmnd was released back to upper layer which could be freed, but the driver is still accessing it. 7 [ffffa8e8d2c3f8d0] page_fault at ffffffff86c010fe [exception RIP: __qla2x00_eh_wait_for_pending_commands+240] RIP: ffffffffc0642350 RSP: ffffa8e8d2c3f988 RFLAGS: 00010286 RAX: 0000000000000165 RBX: 0000000000000002 RCX: 00000000000036d8 RDX: 0000000000000000 RSI: ffff9c5c56535188 RDI: 0000000000000286 RBP: ffff9c5bf7aa4a58 R8: ffff9c589aecdb70 R9: 00000000000003d1 R10: 0000000000000001 R11: 0000000000380000 R12: ffff9c5c5392bc78 R13: ffff9c57044ff5c0 R14: ffff9c56b5a3aa00 R15: 00000000000006db ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 8 [ffffa8e8d2c3f9c8] qla2x00_eh_wait_for_pending_commands at ffffffffc0646dd5 [qla2xxx] 9 [ffffa8e8d2c3fa00] __qla2x00_async_tm_cmd at ffffffffc0658094 [qla2xxx] Remove access of freed memory. Currently the driver was checking to see if scsi_done was called by seeing if the sp->type has changed. Instead, check to see if the command has left the oustanding_cmds[] array as sign of scsi_done was called. Cc: [email protected] Signed-off-by: Quinn Tran <[email protected]> Signed-off-by: Nilesh Javali <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Himanshu Madhani <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 90770da commit d994ac7

File tree

2 files changed

+95
-73
lines changed

2 files changed

+95
-73
lines changed

drivers/scsi/qla2xxx/qla_isr.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,9 +1862,9 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
18621862
}
18631863
}
18641864

1865-
srb_t *
1866-
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
1867-
struct req_que *req, void *iocb)
1865+
static srb_t *
1866+
qla_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
1867+
struct req_que *req, void *iocb, u16 *ret_index)
18681868
{
18691869
struct qla_hw_data *ha = vha->hw;
18701870
sts_entry_t *pkt = iocb;
@@ -1899,12 +1899,25 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
18991899
return NULL;
19001900
}
19011901

1902-
req->outstanding_cmds[index] = NULL;
1903-
1902+
*ret_index = index;
19041903
qla_put_fw_resources(sp->qpair, &sp->iores);
19051904
return sp;
19061905
}
19071906

1907+
srb_t *
1908+
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
1909+
struct req_que *req, void *iocb)
1910+
{
1911+
uint16_t index;
1912+
srb_t *sp;
1913+
1914+
sp = qla_get_sp_from_handle(vha, func, req, iocb, &index);
1915+
if (sp)
1916+
req->outstanding_cmds[index] = NULL;
1917+
1918+
return sp;
1919+
}
1920+
19081921
static void
19091922
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
19101923
struct mbx_entry *mbx)
@@ -3237,13 +3250,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
32373250
return;
32383251
}
32393252

3240-
req->outstanding_cmds[handle] = NULL;
32413253
cp = GET_CMD_SP(sp);
32423254
if (cp == NULL) {
32433255
ql_dbg(ql_dbg_io, vha, 0x3018,
32443256
"Command already returned (0x%x/%p).\n",
32453257
sts->handle, sp);
32463258

3259+
req->outstanding_cmds[handle] = NULL;
32473260
return;
32483261
}
32493262

@@ -3514,6 +3527,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
35143527

35153528
if (rsp->status_srb == NULL)
35163529
sp->done(sp, res);
3530+
3531+
/* for io's, clearing of outstanding_cmds[handle] means scsi_done was called */
3532+
req->outstanding_cmds[handle] = NULL;
35173533
}
35183534

35193535
/**
@@ -3590,6 +3606,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
35903606
uint16_t que = MSW(pkt->handle);
35913607
struct req_que *req = NULL;
35923608
int res = DID_ERROR << 16;
3609+
u16 index;
35933610

35943611
ql_dbg(ql_dbg_async, vha, 0x502a,
35953612
"iocb type %xh with error status %xh, handle %xh, rspq id %d\n",
@@ -3608,7 +3625,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
36083625

36093626
switch (pkt->entry_type) {
36103627
case NOTIFY_ACK_TYPE:
3611-
case STATUS_TYPE:
36123628
case STATUS_CONT_TYPE:
36133629
case LOGINOUT_PORT_IOCB_TYPE:
36143630
case CT_IOCB_TYPE:
@@ -3628,6 +3644,14 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
36283644
case CTIO_TYPE7:
36293645
case CTIO_CRC2:
36303646
return 1;
3647+
case STATUS_TYPE:
3648+
sp = qla_get_sp_from_handle(vha, func, req, pkt, &index);
3649+
if (sp) {
3650+
sp->done(sp, res);
3651+
req->outstanding_cmds[index] = NULL;
3652+
return 0;
3653+
}
3654+
break;
36313655
}
36323656
fatal:
36333657
ql_log(ql_log_warn, vha, 0x5030,

drivers/scsi/qla2xxx/qla_os.c

Lines changed: 64 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,43 +1068,6 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
10681068
return 0;
10691069
}
10701070

1071-
/*
1072-
* qla2x00_eh_wait_on_command
1073-
* Waits for the command to be returned by the Firmware for some
1074-
* max time.
1075-
*
1076-
* Input:
1077-
* cmd = Scsi Command to wait on.
1078-
*
1079-
* Return:
1080-
* Completed in time : QLA_SUCCESS
1081-
* Did not complete in time : QLA_FUNCTION_FAILED
1082-
*/
1083-
static int
1084-
qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
1085-
{
1086-
#define ABORT_POLLING_PERIOD 1000
1087-
#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD))
1088-
unsigned long wait_iter = ABORT_WAIT_ITER;
1089-
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
1090-
struct qla_hw_data *ha = vha->hw;
1091-
srb_t *sp = scsi_cmd_priv(cmd);
1092-
int ret = QLA_SUCCESS;
1093-
1094-
if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) {
1095-
ql_dbg(ql_dbg_taskm, vha, 0x8005,
1096-
"Return:eh_wait.\n");
1097-
return ret;
1098-
}
1099-
1100-
while (sp->type && wait_iter--)
1101-
msleep(ABORT_POLLING_PERIOD);
1102-
if (sp->type)
1103-
ret = QLA_FUNCTION_FAILED;
1104-
1105-
return ret;
1106-
}
1107-
11081071
/*
11091072
* qla2x00_wait_for_hba_online
11101073
* Wait till the HBA is online after going through
@@ -1355,6 +1318,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
13551318
return ret;
13561319
}
13571320

1321+
#define ABORT_POLLING_PERIOD 1000
1322+
#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD))
1323+
13581324
/*
13591325
* Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED.
13601326
*/
@@ -1368,41 +1334,73 @@ __qla2x00_eh_wait_for_pending_commands(struct qla_qpair *qpair, unsigned int t,
13681334
struct req_que *req = qpair->req;
13691335
srb_t *sp;
13701336
struct scsi_cmnd *cmd;
1337+
unsigned long wait_iter = ABORT_WAIT_ITER;
1338+
bool found;
1339+
struct qla_hw_data *ha = vha->hw;
13711340

13721341
status = QLA_SUCCESS;
13731342

1374-
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
1375-
for (cnt = 1; status == QLA_SUCCESS &&
1376-
cnt < req->num_outstanding_cmds; cnt++) {
1377-
sp = req->outstanding_cmds[cnt];
1378-
if (!sp)
1379-
continue;
1380-
if (sp->type != SRB_SCSI_CMD)
1381-
continue;
1382-
if (vha->vp_idx != sp->vha->vp_idx)
1383-
continue;
1384-
match = 0;
1385-
cmd = GET_CMD_SP(sp);
1386-
switch (type) {
1387-
case WAIT_HOST:
1388-
match = 1;
1389-
break;
1390-
case WAIT_TARGET:
1391-
match = cmd->device->id == t;
1392-
break;
1393-
case WAIT_LUN:
1394-
match = (cmd->device->id == t &&
1395-
cmd->device->lun == l);
1396-
break;
1397-
}
1398-
if (!match)
1399-
continue;
1343+
while (wait_iter--) {
1344+
found = false;
14001345

1401-
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
1402-
status = qla2x00_eh_wait_on_command(cmd);
14031346
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
1347+
for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
1348+
sp = req->outstanding_cmds[cnt];
1349+
if (!sp)
1350+
continue;
1351+
if (sp->type != SRB_SCSI_CMD)
1352+
continue;
1353+
if (vha->vp_idx != sp->vha->vp_idx)
1354+
continue;
1355+
match = 0;
1356+
cmd = GET_CMD_SP(sp);
1357+
switch (type) {
1358+
case WAIT_HOST:
1359+
match = 1;
1360+
break;
1361+
case WAIT_TARGET:
1362+
if (sp->fcport)
1363+
match = sp->fcport->d_id.b24 == t;
1364+
else
1365+
match = 0;
1366+
break;
1367+
case WAIT_LUN:
1368+
if (sp->fcport)
1369+
match = (sp->fcport->d_id.b24 == t &&
1370+
cmd->device->lun == l);
1371+
else
1372+
match = 0;
1373+
break;
1374+
}
1375+
if (!match)
1376+
continue;
1377+
1378+
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
1379+
1380+
if (unlikely(pci_channel_offline(ha->pdev)) ||
1381+
ha->flags.eeh_busy) {
1382+
ql_dbg(ql_dbg_taskm, vha, 0x8005,
1383+
"Return:eh_wait.\n");
1384+
return status;
1385+
}
1386+
1387+
/*
1388+
* SRB_SCSI_CMD is still in the outstanding_cmds array.
1389+
* it means scsi_done has not called. Wait for it to
1390+
* clear from outstanding_cmds.
1391+
*/
1392+
msleep(ABORT_POLLING_PERIOD);
1393+
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
1394+
found = true;
1395+
}
1396+
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
1397+
1398+
if (!found)
1399+
break;
14041400
}
1405-
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
1401+
1402+
if (!wait_iter && found)
1403+
status = QLA_FUNCTION_FAILED;
14061404

14071405
return status;
14081406
}

0 commit comments

Comments
 (0)