[PATCH v1] block/mq-deadline: hold elevator_lock in debugfs next_rq show

Xixin Liu <[email protected]>
Newsgroups org.kernel.vger.linux-block,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
deadline_*_next_rq_show() dereferences q->elevator->elevator_data without
holding elevator_lock.  Concurrent elevator switch to "none" clears
q->elevator under that lock and tears down the scheduler, so readers
crash with a null-ptr-deref.

Hold elevator_lock around the show path and bail out if the elevator has
already been removed, matching other blk-mq debugfs readers that look at
elevator state.

Reproduced on linux-next with KASAN by reading write1_next_rq via debugfs
while switching the elevator from mq-deadline to none under fio load:

 BUG: KASAN: null-ptr-deref in deadline_write1_next_rq_show+0x3c/0xf0
 Read of size 8 at addr 0000000000000010 by task cat/140857
 Call trace:
  deadline_write1_next_rq_show+0x3c/0xf0
  blk_mq_debugfs_show+0x58/0x78
  seq_read_iter+0x254/0x6f8
  seq_read+0x1a0/0x220
  vfs_read+0x14c/0x528

Signed-off-by: Xixin Liu <[email protected]>
---
 block/mq-deadline.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/block/mq-deadline.c b/block/mq-deadline.c
index 824bfc17b2c6..e7c4a91b2d08 100644
--- a/block/mq-deadline.c
+++ b/block/mq-deadline.c
@@ -842,14 +842,22 @@ static int deadline_##name##_next_rq_show(void *data,			\
 					  struct seq_file *m)		\
 {									\
 	struct request_queue *q = data;					\
-	struct deadline_data *dd = q->elevator->elevator_data;		\
-	struct dd_per_prio *per_prio = &dd->per_prio[prio];		\
+	struct elevator_queue *e;					\
+	struct deadline_data *dd;					\
+	struct dd_per_prio *per_prio;					\
 	struct request *rq;						\
+	int ret;							\
 									\
+	ret = mutex_lock_interruptible(&q->elevator_lock);		\
+	if (ret)							\
+		return ret;						\
+	e = q->elevator;						\
+	if (!e)								\
+		goto unlock;						\
+	dd = e->elevator_data;						\
+	per_prio = &dd->per_prio[prio];					\
 	rq = deadline_from_pos(per_prio, data_dir,			\
 			       per_prio->latest_pos[data_dir]);		\
 	if (rq)								\
 		__blk_mq_debugfs_rq_show(m, rq);			\
+unlock:									\
+	mutex_unlock(&q->elevator_lock);				\
 	return 0;							\
 }
 
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.