Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 715848ca authored by Andrew Vasquez's avatar Andrew Vasquez Committed by James Bottomley
Browse files

[SCSI] qla2xxx: Correct use-after-free issue in terminate_rport_io callback.



The explicit logout (LOGO) issued at the end of the callback will
flush (via normal scsi_cmnd->done()) any outstanding commands
(FCP2) the firmware is holding.  While iterating through the
outstanding_cmnd array in qla2x00_abort_fcport_cmds(), locking
and unlocking of the hardware spinlock, opens-up the driver to
cases where the processed SRB (sp) could be used after the
command completed from interrupt context.

Cc: stable@kernel.org
Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 55e5ed27
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -1531,8 +1531,6 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
		fcport->vha->hw->isp_ops->fabric_logout(fcport->vha,
			fcport->loop_id, fcport->d_id.b.domain,
			fcport->d_id.b.area, fcport->d_id.b.al_pa);

	qla2x00_abort_fcport_cmds(fcport);
}

static int
+0 −1
Original line number Diff line number Diff line
@@ -96,7 +96,6 @@ extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);

extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);

extern void qla2x00_abort_fcport_cmds(fc_port_t *);
extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
	struct qla_hw_data *);
extern void qla2x00_free_host(struct scsi_qla_host *);
+0 −38
Original line number Diff line number Diff line
@@ -682,44 +682,6 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha)
	return (return_status);
}

void
qla2x00_abort_fcport_cmds(fc_port_t *fcport)
{
	int cnt;
	unsigned long flags;
	srb_t *sp;
	scsi_qla_host_t *vha = fcport->vha;
	struct qla_hw_data *ha = vha->hw;
	struct req_que *req;

	spin_lock_irqsave(&ha->hardware_lock, flags);
	req = vha->req;
	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
		sp = req->outstanding_cmds[cnt];
		if (!sp)
			continue;
		if (sp->fcport != fcport)
			continue;
		if (sp->ctx)
			continue;

		spin_unlock_irqrestore(&ha->hardware_lock, flags);
		if (ha->isp_ops->abort_command(sp)) {
			DEBUG2(qla_printk(KERN_WARNING, ha,
			"Abort failed --  %lx\n",
			sp->cmd->serial_number));
		} else {
			if (qla2x00_eh_wait_on_command(sp->cmd) !=
				QLA_SUCCESS)
				DEBUG2(qla_printk(KERN_WARNING, ha,
				"Abort failed while waiting --  %lx\n",
				sp->cmd->serial_number));
		}
		spin_lock_irqsave(&ha->hardware_lock, flags);
	}
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
}

/**************************************************************************
* qla2xxx_eh_abort
*