scsi: libsas: fix a race condition when smp task timeout [Linux 3.16.72]

This Linux kernel change "scsi: libsas: fix a race condition when smp task timeout" is included in the Linux 3.16.72 release. This change is authored by Jason Yan <yanaijie [at] huawei.com> on Tue Sep 25 10:56:54 2018 +0800. The commit for this change in Linux stable tree is d5534b2 (patch) which is from upstream commit b90cd6f. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream b90cd6f.

scsi: libsas: fix a race condition when smp task timeout

commit b90cd6f2b905905fb42671009dc0e27c310a16ae upstream.

When the lldd is processing the complete sas task in interrupt and set the
task stat as SAS_TASK_STATE_DONE, the smp timeout timer is able to be
triggered at the same time. And smp_task_timedout() will complete the task
wheter the SAS_TASK_STATE_DONE is set or not. Then the sas task may freed
before lldd end the interrupt process. Thus a use-after-free will happen.

Fix this by calling the complete() only when SAS_TASK_STATE_DONE is not
set. And remove the check of the return value of the del_timer(). Once the
LLDD sets DONE, it must call task->done(), which will call
smp_task_done()->complete() and the task will be completed and freed
correctly.

Reported-by: chenxiang <chenxiang66@hisilicon.com>
Signed-off-by: Jason Yan <yanaijie@huawei.com>
CC: John Garry <john.garry@huawei.com>
CC: Johannes Thumshirn <jthumshirn@suse.de>
CC: Ewan Milne <emilne@redhat.com>
CC: Christoph Hellwig <hch@lst.de>
CC: Tomas Henzl <thenzl@redhat.com>
CC: Dan Williams <dan.j.williams@intel.com>
CC: Hannes Reinecke <hare@suse.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: John Garry <john.garry@huawei.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>

There are 9 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/scsi/libsas/sas_expander.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 7d5d66e..65826111 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -47,17 +47,16 @@ static void smp_task_timedout(unsigned long _task)
    unsigned long flags;

    spin_lock_irqsave(&task->task_state_lock, flags);
-   if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+   if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
        task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+       complete(&task->slow_task->completion);
+   }
    spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-   complete(&task->slow_task->completion);
 }

 static void smp_task_done(struct sas_task *task)
 {
-   if (!del_timer(&task->slow_task->timer))
-       return;
+   del_timer(&task->slow_task->timer);
    complete(&task->slow_task->completion);
 }

Leave a Reply

Your email address will not be published. Required fields are marked *