Skip to contentSkip to conversation

blkmq: Fix NULL pointer deref when all reserved tags in use

PATCH Superseded Sam Bradshaw 2 participants 4 messages Mar 18, 2015 Block layer

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 blkmq: Fix NULL pointer deref when all reserved tags in use

When allocating from the reserved tags pool, bt_get() is called with a NULL hctx. If all tags are in use, the hw queue is kicked to push out any pending IO, potentially freeing tags, and tag allocation is retried. The problem is that blk_mq_run_hw_queue() doesn't check for a NULL hctx. This patch fixes that bug.

An alternative implementation might skip kicking the queue for reserved tags and go right to io_schedule() but we chose to keep it simple.

Tested by hammering mtip32xx with concurrent smartctl/hdparm.

---
 block/blk-mq.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
block/blk-mq.c +1 -1
index 59fa239..0471af6 100644
@@ -887,7 +887,7 @@ static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx)
 
 void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
 {
-	if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state) ||
+	if (unlikely(!hctx || test_bit(BLK_MQ_S_STOPPED, &hctx->state) ||
 	    !blk_mq_hw_queue_mapped(hctx)))
 		return;
 
Signature · 1 line
1.7.1
maintainer
#1 lore raw
Quoted 22 lines · Sam Bradshaw

When allocating from the reserved tags pool, bt_get() is called with a NULL hctx. If all tags are in use, the hw queue is kicked to push out any pending IO, potentially freeing tags, and tag allocation is retried. The problem is that blk_mq_run_hw_queue() doesn't check for a NULL hctx. This patch fixes that bug.

An alternative implementation might skip kicking the queue for reserved tags and go right to io_schedule() but we chose to keep it simple.

Tested by hammering mtip32xx with concurrent smartctl/hdparm.

---
  block/blk-mq.c |    2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)
block/blk-mq.c +0 -0
index 59fa239..0471af6 100644

block/blk-mq.c static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx) · line 892

Quoted 7 lines
block/blk-mq.c +1 -1
@@ -887,7 +887,7 @@ static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx)
 
  void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
  {
-	if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state) ||
+	if (unlikely(!hctx || test_bit(BLK_MQ_S_STOPPED, &hctx->state) ||
  	    !blk_mq_hw_queue_mapped(hctx)))
  		return;

Good catch! But why not put the hctx == NULL check in as a conditional in bt_get() before running the queue? I can't imagine other cases where calling blk_mq_run_hw_queue() with hctx == NULL would be a valid scenario.

The bug was introduced with commit b32232073e80, so that should probably be indicated too.

Signature · 1 line
Jens Axboe
#2 lore raw
Quoted 4 lines

Good catch! But why not put the hctx == NULL check in as a conditional in bt_get() before running the queue? I can't imagine other cases where calling blk_mq_run_hw_queue() with hctx == NULL would be a valid scenario.

The change was meant to be broad in scope. A runtime NULL deref is a rather unfortunate way to determine that there are other invalid scenarios.

But given that both approaches fix the immediate problem, I'd be happy to change the patch as you suggest.

maintainer
#3 lore raw
Quoted 8 lines · Sam Bradshaw
Quoted 5 lines

Good catch! But why not put the hctx == NULL check in as a conditional in bt_get() before running the queue? I can't imagine other cases where calling blk_mq_run_hw_queue() with hctx == NULL would be a valid scenario.

The change was meant to be broad in scope. A runtime NULL deref is a rather unfortunate way to determine that there are other invalid scenarios.

Normally those kinds of issues would trigger quickly and it'd be obvious. Granted, this was an error handling case for the special case of reserved tags, so it persisted longer than it should have... But in general, I would not be too worried.

Quoted 2 lines

But given that both approaches fix the immediate problem, I'd be happy to change the patch as you suggest.

Thanks!

Signature · 1 line
Jens Axboe