OSDN Git Service

scsi: iscsi: Fix iscsi_task use after free
authorMike Christie <michael.christie@oracle.com>
Mon, 4 Oct 2021 21:06:08 +0000 (16:06 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 5 Oct 2021 03:40:11 +0000 (23:40 -0400)
Commit d39df158518c ("scsi: iscsi: Have abort handler get ref to conn")
added iscsi_get_conn()/iscsi_put_conn() calls during abort handling but
then also changed the handling of the case where we detect an already
completed task where we now end up doing a goto to the common put/cleanup
code. This results in a iscsi_task use after free, because the common
cleanup code will do a put on the iscsi_task.

This reverts the goto and moves the iscsi_get_conn() to after we've checked
if the iscsi_task is valid.

Link: https://lore.kernel.org/r/20211004210608.9962-1-michael.christie@oracle.com
Fixes: d39df158518c ("scsi: iscsi: Have abort handler get ref to conn")
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/libiscsi.c

index 4683c18..5bc91d3 100644 (file)
@@ -2281,11 +2281,6 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                return FAILED;
        }
 
-       conn = session->leadconn;
-       iscsi_get_conn(conn->cls_conn);
-       conn->eh_abort_cnt++;
-       age = session->age;
-
        spin_lock(&session->back_lock);
        task = (struct iscsi_task *)sc->SCp.ptr;
        if (!task || !task->sc) {
@@ -2293,8 +2288,16 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
                ISCSI_DBG_EH(session, "sc completed while abort in progress\n");
 
                spin_unlock(&session->back_lock);
-               goto success;
+               spin_unlock_bh(&session->frwd_lock);
+               mutex_unlock(&session->eh_mutex);
+               return SUCCESS;
        }
+
+       conn = session->leadconn;
+       iscsi_get_conn(conn->cls_conn);
+       conn->eh_abort_cnt++;
+       age = session->age;
+
        ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", sc, task->itt);
        __iscsi_get_task(task);
        spin_unlock(&session->back_lock);