[ofa-general] Re: sg_reset can trigger a NULL pointer dereference in the SRP initiator
Bart Van Assche
bart.vanassche at gmail.com
Fri Aug 7 01:31:18 PDT 2009
On Thu, Aug 6, 2009 at 7:41 PM, Roland Dreier<rdreier at cisco.com> wrote:
>
> > Specifically scmnd->host_scribble can just be Zero.
>
> I see at last, thanks!
>
> The issue is that SRP is using host_scribble to hold an index, and index
> 0 is valid for us.
>
> I guess the fix is a bit complex, but basically we should use
> host_scribble to point to the request, and if we don't find a request in
> reset_device we should allocate one.
A fix like the one below ?
--- linux-2.6.30.4/drivers/infiniband/ulp/srp/ib_srp-orig.c 2009-08-03
12:13:11.000000000 +0200
+++ linux-2.6.30.4/drivers/infiniband/ulp/srp/ib_srp.c 2009-08-07
10:23:27.000000000 +0200
@@ -1371,16 +1371,27 @@ out:
return -1;
}
+/**
+ * Look up the struct srp_request that has been associated with the specified
+ * SCSI command by srp_queuecommand().
+ *
+ * Returns 0 upon success and -1 upon failure.
+ */
static int srp_find_req(struct srp_target_port *target,
struct scsi_cmnd *scmnd,
struct srp_request **req)
{
- if (scmnd->host_scribble == (void *) -1L)
- return -1;
+ /*
+ * The code below will only work if SRP_RQ_SIZE is a power of two,
+ * so check this first.
+ */
+ BUILD_BUG_ON((SRP_RQ_SIZE ^ (SRP_RQ_SIZE - 1))
+ != (SRP_RQ_SIZE | (SRP_RQ_SIZE - 1)));
- *req = &target->req_ring[(long) scmnd->host_scribble];
+ *req = &target->req_ring[(long)scmnd->host_scribble
+ & (SRP_RQ_SIZE - 1)];
- return 0;
+ return (*req)->scmnd == scmnd ? 0 : -1;
}
static int srp_abort(struct scsi_cmnd *scmnd)
@@ -1423,8 +1434,15 @@ static int srp_reset_device(struct scsi_
if (target->qp_in_error)
return FAILED;
- if (srp_find_req(target, scmnd, &req))
- return FAILED;
+ if (srp_find_req(target, scmnd, &req)) {
+ /*
+ * scmnd has not yet been queued -- queue it now. This can
+ * happen e.g. when a SG_SCSI_RESET ioctl has been issued.
+ */
+ if (srp_queuecommand(scmnd, scmnd->scsi_done)
+ || srp_find_req(target, scmnd, &req))
+ return FAILED;
+ }
if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
return FAILED;
if (req->tsk_status)
More information about the general
mailing list