Skip to content

Commit 20b97ac

Browse files
bvanasschemartinkpetersen
authored andcommitted
scsi: ufs: core: Fix a race condition related to device commands
There is a TOCTOU race in ufshcd_compl_one_cqe(): hba->dev_cmd.complete may be cleared from another thread after it has been checked and before it is used. Fix this race by moving the device command completion from the stack of the device command submitter into struct ufs_hba. This patch fixes the following kernel crash: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008 Call trace: _raw_spin_lock_irqsave+0x34/0x80 complete+0x24/0xb8 ufshcd_compl_one_cqe+0x13c/0x4f0 ufshcd_mcq_poll_cqe_lock+0xb4/0x108 ufshcd_intr+0x2f4/0x444 __handle_irq_event_percpu+0xbc/0x250 handle_irq_event+0x48/0xb0 Fixes: 5a0b0cb ("[SCSI] ufs: Add support for sending NOP OUT UPIU") Signed-off-by: Bart Van Assche <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Peter Wang <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent daff37f commit 20b97ac

File tree

2 files changed

+7
-20
lines changed

2 files changed

+7
-20
lines changed

drivers/ufs/core/ufshcd.c

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3176,16 +3176,10 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
31763176
int err;
31773177

31783178
retry:
3179-
time_left = wait_for_completion_timeout(hba->dev_cmd.complete,
3179+
time_left = wait_for_completion_timeout(&hba->dev_cmd.complete,
31803180
time_left);
31813181

31823182
if (likely(time_left)) {
3183-
/*
3184-
* The completion handler called complete() and the caller of
3185-
* this function still owns the @lrbp tag so the code below does
3186-
* not trigger any race conditions.
3187-
*/
3188-
hba->dev_cmd.complete = NULL;
31893183
err = ufshcd_get_tr_ocs(lrbp, NULL);
31903184
if (!err)
31913185
err = ufshcd_dev_cmd_completion(hba, lrbp);
@@ -3199,7 +3193,6 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
31993193
/* successfully cleared the command, retry if needed */
32003194
if (ufshcd_clear_cmd(hba, lrbp->task_tag) == 0)
32013195
err = -EAGAIN;
3202-
hba->dev_cmd.complete = NULL;
32033196
return err;
32043197
}
32053198

@@ -3215,11 +3208,9 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
32153208
spin_lock_irqsave(&hba->outstanding_lock, flags);
32163209
pending = test_bit(lrbp->task_tag,
32173210
&hba->outstanding_reqs);
3218-
if (pending) {
3219-
hba->dev_cmd.complete = NULL;
3211+
if (pending)
32203212
__clear_bit(lrbp->task_tag,
32213213
&hba->outstanding_reqs);
3222-
}
32233214
spin_unlock_irqrestore(&hba->outstanding_lock, flags);
32243215

32253216
if (!pending) {
@@ -3237,8 +3228,6 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
32373228
spin_lock_irqsave(&hba->outstanding_lock, flags);
32383229
pending = test_bit(lrbp->task_tag,
32393230
&hba->outstanding_reqs);
3240-
if (pending)
3241-
hba->dev_cmd.complete = NULL;
32423231
spin_unlock_irqrestore(&hba->outstanding_lock, flags);
32433232

32443233
if (!pending) {
@@ -3272,13 +3261,9 @@ static void ufshcd_dev_man_unlock(struct ufs_hba *hba)
32723261
static int ufshcd_issue_dev_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp,
32733262
const u32 tag, int timeout)
32743263
{
3275-
DECLARE_COMPLETION_ONSTACK(wait);
32763264
int err;
32773265

3278-
hba->dev_cmd.complete = &wait;
3279-
32803266
ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
3281-
32823267
ufshcd_send_command(hba, tag, hba->dev_cmd_queue);
32833268
err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
32843269

@@ -5585,12 +5570,12 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag,
55855570
ufshcd_release_scsi_cmd(hba, lrbp);
55865571
/* Do not touch lrbp after scsi done */
55875572
scsi_done(cmd);
5588-
} else if (hba->dev_cmd.complete) {
5573+
} else {
55895574
if (cqe) {
55905575
ocs = le32_to_cpu(cqe->status) & MASK_OCS;
55915576
lrbp->utr_descriptor_ptr->header.ocs = ocs;
55925577
}
5593-
complete(hba->dev_cmd.complete);
5578+
complete(&hba->dev_cmd.complete);
55945579
}
55955580
}
55965581

@@ -10475,6 +10460,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1047510460
*/
1047610461
spin_lock_init(&hba->clk_gating.lock);
1047710462

10463+
init_completion(&hba->dev_cmd.complete);
10464+
1047810465
err = ufshcd_hba_init(hba);
1047910466
if (err)
1048010467
goto out_error;

include/ufs/ufshcd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ struct ufs_query {
246246
struct ufs_dev_cmd {
247247
enum dev_cmd_type type;
248248
struct mutex lock;
249-
struct completion *complete;
249+
struct completion complete;
250250
struct ufs_query query;
251251
};
252252

0 commit comments

Comments
 (0)