]>
Commit | Line | Data |
---|---|---|
5a738d03 GKH |
1 | From b90cd6f2b905905fb42671009dc0e27c310a16ae Mon Sep 17 00:00:00 2001 |
2 | From: Jason Yan <yanaijie@huawei.com> | |
3 | Date: Tue, 25 Sep 2018 10:56:54 +0800 | |
4 | Subject: scsi: libsas: fix a race condition when smp task timeout | |
5 | ||
6 | From: Jason Yan <yanaijie@huawei.com> | |
7 | ||
8 | commit b90cd6f2b905905fb42671009dc0e27c310a16ae upstream. | |
9 | ||
10 | When the lldd is processing the complete sas task in interrupt and set the | |
11 | task stat as SAS_TASK_STATE_DONE, the smp timeout timer is able to be | |
12 | triggered at the same time. And smp_task_timedout() will complete the task | |
13 | wheter the SAS_TASK_STATE_DONE is set or not. Then the sas task may freed | |
14 | before lldd end the interrupt process. Thus a use-after-free will happen. | |
15 | ||
16 | Fix this by calling the complete() only when SAS_TASK_STATE_DONE is not | |
17 | set. And remove the check of the return value of the del_timer(). Once the | |
18 | LLDD sets DONE, it must call task->done(), which will call | |
19 | smp_task_done()->complete() and the task will be completed and freed | |
20 | correctly. | |
21 | ||
22 | Reported-by: chenxiang <chenxiang66@hisilicon.com> | |
23 | Signed-off-by: Jason Yan <yanaijie@huawei.com> | |
24 | CC: John Garry <john.garry@huawei.com> | |
25 | CC: Johannes Thumshirn <jthumshirn@suse.de> | |
26 | CC: Ewan Milne <emilne@redhat.com> | |
27 | CC: Christoph Hellwig <hch@lst.de> | |
28 | CC: Tomas Henzl <thenzl@redhat.com> | |
29 | CC: Dan Williams <dan.j.williams@intel.com> | |
30 | CC: Hannes Reinecke <hare@suse.com> | |
31 | Reviewed-by: Hannes Reinecke <hare@suse.com> | |
32 | Reviewed-by: John Garry <john.garry@huawei.com> | |
33 | Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> | |
34 | Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> | |
35 | Cc: Guenter Roeck <linux@roeck-us.net | |
36 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
37 | ||
38 | --- | |
39 | drivers/scsi/libsas/sas_expander.c | 9 ++++----- | |
40 | 1 file changed, 4 insertions(+), 5 deletions(-) | |
41 | ||
42 | --- a/drivers/scsi/libsas/sas_expander.c | |
43 | +++ b/drivers/scsi/libsas/sas_expander.c | |
44 | @@ -47,17 +47,16 @@ static void smp_task_timedout(unsigned l | |
45 | unsigned long flags; | |
46 | ||
47 | spin_lock_irqsave(&task->task_state_lock, flags); | |
48 | - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | |
49 | + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { | |
50 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | |
51 | + complete(&task->slow_task->completion); | |
52 | + } | |
53 | spin_unlock_irqrestore(&task->task_state_lock, flags); | |
54 | - | |
55 | - complete(&task->slow_task->completion); | |
56 | } | |
57 | ||
58 | static void smp_task_done(struct sas_task *task) | |
59 | { | |
60 | - if (!del_timer(&task->slow_task->timer)) | |
61 | - return; | |
62 | + del_timer(&task->slow_task->timer); | |
63 | complete(&task->slow_task->completion); | |
64 | } | |
65 |