[PATCH 5.12] nullb: fix use_after_free on rq timeout

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



// 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@xxxxxxxxx>
---

non-NULL_IRQ_TIMER may also need some patching.

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

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;
 }
 
-- 
2.24.0




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux