diff mbox series

[5.12] nullb: fix use_after_free on rq timeout

Message ID 74a2c9ded02ead5b1fe2332e5f3e7cd2177dba97.1615987901.git.asml.silence@gmail.com (mailing list archive)
State New, archived
Headers show
Series [5.12] nullb: fix use_after_free on rq timeout | expand

Commit Message

Pavel Begunkov March 17, 2021, 1:50 p.m. UTC
// insmod ./null_blk queue_mode=2 irqmode=2 completion_nsec=10000000000

[  332.929595] null_blk: rq 00000000ecf12d66 timed out
[  336.036131] ------------[ cut here ]------------
[  336.036139] refcount_t: underflow; use-after-free.
[  336.036155] WARNING: CPU: 0 PID: 0 at lib/refcount.c:28 refcount_warn_saturate+0xae/0xf0
[  336.036407] RIP: 0010:refcount_warn_saturate+0xae/0xf0
[  336.036467] Call Trace:
[  336.036470]  <IRQ>
[  336.036476]  blk_mq_free_request+0x140/0x150
[  336.036487]  blk_mq_end_request+0x129/0x140
[  336.036496]  end_cmd+0x30/0x80 [null_blk]
[  336.036516]  ? null_complete_rq+0x20/0x20 [null_blk]
[  336.036532]  null_cmd_timer_expired+0x12/0x20 [null_blk]
[  336.036546]  __hrtimer_run_queues+0x10d/0x2a0
[  336.036555]  hrtimer_interrupt+0x109/0x220
[  336.036561]  ? sched_clock_cpu+0x16/0xd0
[  	336.036573]  __sysvec_apic_timer_interrupt+0x69/0x120
[  336.036581]  sysvec_apic_timer_interrupt+0x77/0x90
[  336.036593]  </IRQ>
[  336.036596]  asm_sysvec_apic_timer_interrupt+0x12/0x20
...
[  336.036740] ---[ end trace bfb36b9c4f62fd9a ]---
[  339.756204] null_blk: rq 0000000050397c34 timed out
[  339.756934] null_blk: module loaded

In case of expiried NULL_IRQ_TIMER nullblk requests, first
null_timeout_rq() does blk_mq_complete_request() dropping a ref and not
removing killing cmd->timer, and then cmd->timer fires and gets
underflow in null_cmd_timer_expired(). Cancel hrtimer on blk-mq
request expiration.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---

non-NULL_IRQ_TIMER may also need some patching.

 drivers/block/null_blk/main.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index d6c821d48090..a87c3359f357 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -1451,8 +1451,16 @@  static bool should_requeue_request(struct request *rq)
 
 static enum blk_eh_timer_return null_timeout_rq(struct request *rq, bool res)
 {
+	struct nullb_cmd *cmd = blk_mq_rq_to_pdu(rq);
+
 	pr_info("rq %p timed out\n", rq);
-	blk_mq_complete_request(rq);
+
+	if (cmd->nq->dev->irqmode == NULL_IRQ_TIMER) {
+		if (hrtimer_try_to_cancel(&cmd->timer) != -1)
+			blk_mq_complete_request(rq);
+	} else {
+		blk_mq_complete_request(rq);
+	}
 	return BLK_EH_DONE;
 }