Re: v4.20-rc6: Sporadic use-after-free in bt_iter()

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

 



On Thu, 2018-12-20 at 11:33 -0700, Jens Axboe wrote:
+AD4 +AFs ... +AF0
+AD4 Something like this, totally untested. If the queue matches, we know it's
+AD4 safe to dereference it.
+AD4 
+AD4 A safer API to export as well...
+AD4 
+AD4 
+AD4 diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
+AD4 index 2089c6c62f44..78192b544fa2 100644
+AD4 --- a/block/blk-mq-tag.c
+AD4 +-+-+- b/block/blk-mq-tag.c
+AD4 +AEAAQA -228,13 +-228,15 +AEAAQA static bool bt+AF8-iter(struct sbitmap +ACo-bitmap, unsigned int bitnr, void +ACo-data)
+AD4  
+AD4  	if (+ACE-reserved)
+AD4  		bitnr +-+AD0 tags-+AD4-nr+AF8-reserved+AF8-tags+ADs
+AD4 -	rq +AD0 tags-+AD4-rqs+AFs-bitnr+AF0AOw
+AD4 +-	if (tags-+AD4-rqs+AFs-bitnr+AF0.queue +ACEAPQ hctx-+AD4-queue)
+AD4 +-		return true+ADs
+AD4  
+AD4  	/+ACo
+AD4  	 +ACo We can hit rq +AD0APQ NULL here, because the tagging functions
+AD4  	 +ACo test and set the bit before assigning -+AD4-rqs+AFsAXQ.
+AD4  	 +ACo-/
+AD4 -	if (rq +ACYAJg rq-+AD4-q +AD0APQ hctx-+AD4-queue)
+AD4 +-	rq +AD0 tags-+AD4-rqs+AFs-bitnr+AF0.rq+ADs
+AD4 +-	if (rq)
+AD4  		return iter+AF8-data-+AD4-fn(hctx, rq, iter+AF8-data-+AD4-data, reserved)+ADs
+AD4  	return true+ADs
+AD4  +AH0
+AD4 +AEAAQA -268,6 +-270,7 +AEAAQA static void bt+AF8-for+AF8-each(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx, struct sbitmap+AF8-queue +ACo-bt,
+AD4  
+AD4  struct bt+AF8-tags+AF8-iter+AF8-data +AHs
+AD4  	struct blk+AF8-mq+AF8-tags +ACo-tags+ADs
+AD4 +-	struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx+ADs
+AD4  	busy+AF8-tag+AF8-iter+AF8-fn +ACo-fn+ADs
+AD4  	void +ACo-data+ADs
+AD4  	bool reserved+ADs
+AD4 +AEAAQA -287,7 +-290,7 +AEAAQA static bool bt+AF8-tags+AF8-iter(struct sbitmap +ACo-bitmap, unsigned int bitnr, void +ACo-data)
+AD4  	 +ACo We can hit rq +AD0APQ NULL here, because the tagging functions
+AD4  	 +ACo test and set the bit before assining -+AD4-rqs+AFsAXQ.
+AD4  	 +ACo-/
+AD4 -	rq +AD0 tags-+AD4-rqs+AFs-bitnr+AF0AOw
+AD4 +-	rq +AD0 tags-+AD4-rqs+AFs-bitnr+AF0.rq+ADs
+AD4  	if (rq +ACYAJg blk+AF8-mq+AF8-request+AF8-started(rq))
+AD4  		return iter+AF8-data-+AD4-fn(rq, iter+AF8-data-+AD4-data, reserved)+ADs
+AD4  
+AD4 diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h
+AD4 index 61deab0b5a5a..bb84d1f099c7 100644
+AD4 --- a/block/blk-mq-tag.h
+AD4 +-+-+- b/block/blk-mq-tag.h
+AD4 +AEAAQA -4,6 +-4,11 +AEAAQA
+AD4  
+AD4  +ACM-include +ACI-blk-mq.h+ACI
+AD4  
+AD4 +-struct rq+AF8-tag+AF8-entry +AHs
+AD4 +-	struct request+AF8-queue +ACo-queue+ADs
+AD4 +-	struct request +ACo-rq+ADs
+AD4 +-+AH0AOw
+AD4 +-
+AD4  /+ACo
+AD4   +ACo Tag address space map.
+AD4   +ACo-/
+AD4 +AEAAQA -16,7 +-21,7 +AEAAQA struct blk+AF8-mq+AF8-tags +AHs
+AD4  	struct sbitmap+AF8-queue bitmap+AF8-tags+ADs
+AD4  	struct sbitmap+AF8-queue breserved+AF8-tags+ADs
+AD4  
+AD4 -	struct request +ACoAKg-rqs+ADs
+AD4 +-	struct rq+AF8-tag+AF8-entry +ACo-rqs+ADs
+AD4  	struct request +ACoAKg-static+AF8-rqs+ADs
+AD4  	struct list+AF8-head page+AF8-list+ADs
+AD4  +AH0AOw
+AD4 +AEAAQA -78,7 +-83,8 +AEAAQA static inline void blk+AF8-mq+AF8-tag+AF8-idle(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx)
+AD4  static inline void blk+AF8-mq+AF8-tag+AF8-set+AF8-rq(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx,
+AD4  		unsigned int tag, struct request +ACo-rq)
+AD4  +AHs
+AD4 -	hctx-+AD4-tags-+AD4-rqs+AFs-tag+AF0 +AD0 rq+ADs
+AD4 +-	hctx-+AD4-tags-+AD4-rqs+AFs-tag+AF0.queue +AD0 hctx-+AD4-queue+ADs
+AD4 +-	hctx-+AD4-tags-+AD4-rqs+AFs-tag+AF0.rq +AD0 rq+ADs
+AD4  +AH0
+AD4  
+AD4  static inline bool blk+AF8-mq+AF8-tag+AF8-is+AF8-reserved(struct blk+AF8-mq+AF8-tags +ACo-tags,
+AD4 diff --git a/block/blk-mq.c b/block/blk-mq.c
+AD4 index 3ba37b9e15e9..4f194946dbd9 100644
+AD4 --- a/block/blk-mq.c
+AD4 +-+-+- b/block/blk-mq.c
+AD4 +AEAAQA -298,13 +-298,16 +AEAAQA static struct request +ACo-blk+AF8-mq+AF8-rq+AF8-ctx+AF8-init(struct blk+AF8-mq+AF8-alloc+AF8-data +ACo-data,
+AD4  		rq-+AD4-tag +AD0 -1+ADs
+AD4  		rq-+AD4-internal+AF8-tag +AD0 tag+ADs
+AD4  	+AH0 else +AHs
+AD4 -		if (data-+AD4-hctx-+AD4-flags +ACY BLK+AF8-MQ+AF8-F+AF8-TAG+AF8-SHARED) +AHs
+AD4 +-		struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx +AD0 data-+AD4-hctx+ADs
+AD4 +-
+AD4 +-		if (hctx-+AD4-flags +ACY BLK+AF8-MQ+AF8-F+AF8-TAG+AF8-SHARED) +AHs
+AD4  			rq+AF8-flags +AD0 RQF+AF8-MQ+AF8-INFLIGHT+ADs
+AD4 -			atomic+AF8-inc(+ACY-data-+AD4-hctx-+AD4-nr+AF8-active)+ADs
+AD4 +-			atomic+AF8-inc(+ACY-hctx-+AD4-nr+AF8-active)+ADs
+AD4  		+AH0
+AD4  		rq-+AD4-tag +AD0 tag+ADs
+AD4  		rq-+AD4-internal+AF8-tag +AD0 -1+ADs
+AD4 -		data-+AD4-hctx-+AD4-tags-+AD4-rqs+AFs-rq-+AD4-tag+AF0 +AD0 rq+ADs
+AD4 +-		hctx-+AD4-tags-+AD4-rqs+AFs-rq-+AD4-tag+AF0.queue +AD0 hctx-+AD4-queue+ADs
+AD4 +-		hctx-+AD4-tags-+AD4-rqs+AFs-rq-+AD4-tag+AF0.rq +AD0 rq+ADs
+AD4  	+AH0
+AD4  
+AD4  	/+ACo csd/requeue+AF8-work/fifo+AF8-time is initialized before use +ACo-/
+AD4 +AEAAQA -797,8 +-800,8 +AEAAQA EXPORT+AF8-SYMBOL(blk+AF8-mq+AF8-delay+AF8-kick+AF8-requeue+AF8-list)+ADs
+AD4  struct request +ACo-blk+AF8-mq+AF8-tag+AF8-to+AF8-rq(struct blk+AF8-mq+AF8-tags +ACo-tags, unsigned int tag)
+AD4  +AHs
+AD4  	if (tag +ADw tags-+AD4-nr+AF8-tags) +AHs
+AD4 -		prefetch(tags-+AD4-rqs+AFs-tag+AF0)+ADs
+AD4 -		return tags-+AD4-rqs+AFs-tag+AF0AOw
+AD4 +-		prefetch(tags-+AD4-rqs+AFs-tag+AF0.rq)+ADs
+AD4 +-		return tags-+AD4-rqs+AFs-tag+AF0.rq+ADs
+AD4  	+AH0
+AD4  
+AD4  	return NULL+ADs
+AD4 +AEAAQA -809,10 +-812,11 +AEAAQA static bool blk+AF8-mq+AF8-rq+AF8-inflight(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx, struct request +ACo-rq,
+AD4  			       void +ACo-priv, bool reserved)
+AD4  +AHs
+AD4  	/+ACo
+AD4 -	 +ACo If we find a request that is inflight and the queue matches,
+AD4 -	 +ACo we know the queue is busy. Return false to stop the iteration.
+AD4 +-	 +ACo We're only called here if the queue matches. If the rq state is
+AD4 +-	 +ACo inflight, we know the queue is busy. Return false to stop the
+AD4 +-	 +ACo iteration.
+AD4  	 +ACo-/
+AD4 -	if (rq-+AD4-state +AD0APQ MQ+AF8-RQ+AF8-IN+AF8-FLIGHT +ACYAJg rq-+AD4-q +AD0APQ hctx-+AD4-queue) +AHs
+AD4 +-	if (rq-+AD4-state +AD0APQ MQ+AF8-RQ+AF8-IN+AF8-FLIGHT) +AHs
+AD4  		bool +ACo-busy +AD0 priv+ADs
+AD4  
+AD4  		+ACo-busy +AD0 true+ADs
+AD4 +AEAAQA -1049,11 +-1053,14 +AEAAQA bool blk+AF8-mq+AF8-get+AF8-driver+AF8-tag(struct request +ACo-rq)
+AD4  	shared +AD0 blk+AF8-mq+AF8-tag+AF8-busy(data.hctx)+ADs
+AD4  	rq-+AD4-tag +AD0 blk+AF8-mq+AF8-get+AF8-tag(+ACY-data)+ADs
+AD4  	if (rq-+AD4-tag +AD4APQ 0) +AHs
+AD4 +-		struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx +AD0 data.hctx+ADs
+AD4 +-
+AD4  		if (shared) +AHs
+AD4  			rq-+AD4-rq+AF8-flags +AHwAPQ RQF+AF8-MQ+AF8-INFLIGHT+ADs
+AD4  			atomic+AF8-inc(+ACY-data.hctx-+AD4-nr+AF8-active)+ADs
+AD4  		+AH0
+AD4 -		data.hctx-+AD4-tags-+AD4-rqs+AFs-rq-+AD4-tag+AF0 +AD0 rq+ADs
+AD4 +-		hctx-+AD4-tags-+AD4-rqs+AFs-rq-+AD4-tag+AF0.queue +AD0 hctx-+AD4-queue+ADs
+AD4 +-		hctx-+AD4-tags-+AD4-rqs+AFs-rq-+AD4-tag+AF0.rq +AD0 rq+ADs
+AD4  	+AH0
+AD4  
+AD4  done:
+AD4 +AEAAQA -2069,7 +-2076,7 +AEAAQA struct blk+AF8-mq+AF8-tags +ACo-blk+AF8-mq+AF8-alloc+AF8-rq+AF8-map(struct blk+AF8-mq+AF8-tag+AF8-set +ACo-set,
+AD4  	if (+ACE-tags)
+AD4  		return NULL+ADs
+AD4  
+AD4 -	tags-+AD4-rqs +AD0 kcalloc+AF8-node(nr+AF8-tags, sizeof(struct request +ACo),
+AD4 +-	tags-+AD4-rqs +AD0 kcalloc+AF8-node(nr+AF8-tags, sizeof(struct rq+AF8-tag+AF8-entry),
+AD4  				 GFP+AF8-NOIO +AHw +AF8AXw-GFP+AF8-NOWARN +AHw +AF8AXw-GFP+AF8-NORETRY,
+AD4  				 node)+ADs
+AD4  	if (+ACE-tags-+AD4-rqs) +AHs

Hi Jens,

How about the patch below? Its behavior should be similar to your patch but I think
this patch is simpler.

Thanks,

Bart.


---
 block/blk-mq.c +AHw 18 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+---
 1 file changed, 16 insertions(+-), 2 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index 6a7566244de3..c57611b1f2a8 100644
--- a/block/blk-mq.c
+-+-+- b/block/blk-mq.c
+AEAAQA -86,6 +-86,7 +AEAAQA static void blk+AF8-mq+AF8-hctx+AF8-clear+AF8-pending(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx,
 +AH0
 
 struct mq+AF8-inflight +AHs
+-	struct request+AF8-queue +ACo-q+ADs
 	struct hd+AF8-struct +ACo-part+ADs
 	unsigned int +ACo-inflight+ADs
 +AH0AOw
+AEAAQA -96,6 +-97,9 +AEAAQA static void blk+AF8-mq+AF8-check+AF8-inflight(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx,
 +AHs
 	struct mq+AF8-inflight +ACo-mi +AD0 priv+ADs
 
+-	if (rq-+AD4-q +ACEAPQ mi-+AD4-q)
+-		return+ADs
+-
 	/+ACo
 	 +ACo index+AFs-0+AF0 counts the specific partition that was asked for. index+AFs-1+AF0
 	 +ACo counts the ones that are active on the whole device, so increment
+AEAAQA -110,7 +-114,11 +AEAAQA static void blk+AF8-mq+AF8-check+AF8-inflight(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx,
 void blk+AF8-mq+AF8-in+AF8-flight(struct request+AF8-queue +ACo-q, struct hd+AF8-struct +ACo-part,
 		      unsigned int inflight+AFs-2+AF0)
 +AHs
-	struct mq+AF8-inflight mi +AD0 +AHs .part +AD0 part, .inflight +AD0 inflight, +AH0AOw
+-	struct mq+AF8-inflight mi +AD0 +AHs
+-		.q +AD0 q,
+-		.part +AD0 part,
+-		.inflight +AD0 inflight,
+-	+AH0AOw
 
 	inflight+AFs-0+AF0 +AD0 inflight+AFs-1+AF0 +AD0 0+ADs
 	blk+AF8-mq+AF8-queue+AF8-tag+AF8-busy+AF8-iter(q, blk+AF8-mq+AF8-check+AF8-inflight, +ACY-mi)+ADs
+AEAAQA -129,7 +-137,11 +AEAAQA static void blk+AF8-mq+AF8-check+AF8-inflight+AF8-rw(struct blk+AF8-mq+AF8-hw+AF8-ctx +ACo-hctx,
 void blk+AF8-mq+AF8-in+AF8-flight+AF8-rw(struct request+AF8-queue +ACo-q, struct hd+AF8-struct +ACo-part,
 			 unsigned int inflight+AFs-2+AF0)
 +AHs
-	struct mq+AF8-inflight mi +AD0 +AHs .part +AD0 part, .inflight +AD0 inflight, +AH0AOw
+-	struct mq+AF8-inflight mi +AD0 +AHs
+-		.q +AD0 q,
+-		.part +AD0 part,
+-		.inflight +AD0 inflight,
+-	+AH0AOw
 
 	inflight+AFs-0+AF0 +AD0 inflight+AFs-1+AF0 +AD0 0+ADs
 	blk+AF8-mq+AF8-queue+AF8-tag+AF8-busy+AF8-iter(q, blk+AF8-mq+AF8-check+AF8-inflight+AF8-rw, +ACY-mi)+ADs
+AEAAQA -477,6 +-489,8 +AEAAQA static void +AF8AXw-blk+AF8-mq+AF8-free+AF8-request(struct request +ACo-rq)
 	const int sched+AF8-tag +AD0 rq-+AD4-internal+AF8-tag+ADs
 
 	blk+AF8-pm+AF8-mark+AF8-last+AF8-busy(rq)+ADs
+-	/+ACo Avoid that blk+AF8-mq+AF8-queue+AF8-tag+AF8-busy+AF8-iter() picks up this request. +ACo-/
+-	rq-+AD4-q +AD0 NULL+ADs
 	if (rq-+AD4-tag +ACEAPQ -1)
 		blk+AF8-mq+AF8-put+AF8-tag(hctx, hctx-+AD4-tags, ctx, rq-+AD4-tag)+ADs
 	if (sched+AF8-tag +ACEAPQ -1)





[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