public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] block: blk-mq: fix UAF in blk_mq_tagset_busy_iter
@ 2026-04-30  4:28 l1za0.sec
  2026-04-30 16:11 ` Bart Van Assche
  0 siblings, 1 reply; 2+ messages in thread
From: l1za0.sec @ 2026-04-30  4:28 UTC (permalink / raw)
  To: axboe; +Cc: linux-block, linux-kernel

From: Haocheng Yu <l1za0.sec@gmail.com>

A KASAN: slab-use-after-free Read in blk_mq_tagset_busy_iter is
reported by a modified Syzkaller-based kernel fuzzing tool we
developed.

This problem is caused by a race condition between
block/blk-mq-tag.c/blk_mq_tagset_busy_iter() and
block/blk-mq.c/blk_mq_realloc_tag_set_tags(). In
blk_mq_realloc_tag_set_tags(), set->tags is first freed, and then
new_tags is assigned to set->tags. However, this process is not
protected by synchronization. Therefore, if another process reads
tagset->tags in blk_mq_tagset_busy_iter() between these two steps,
it will cause a use-after-free read problem.

To fix this vulnerability, first save the old set->tags. After
updating set->tags to new_tags, wait for the reading side to exit
before releasing it. This avoids the problem of tagset->tags being
directly released while blk_mq_tagset_busy_iter() is still iterating.

Signed-off-by: Haocheng Yu <l1za0.sec@gmail.com>
---
The full reproducer is attached here:

# {Threaded:true Repeat:true RepeatTimes:0 Procs:8 Slowdown:1 Sandbox:none SandboxArg:0 Leak:false NetInjection:true NetDevices:true NetReset:true Cgroups:true BinfmtMisc:true CloseFDs:true KCSAN:false DevlinkPCI:false NicVF:false USB:true VhciInjection:true Wifi:true IEEE802154:true Sysctl:true Swap:true UseTmpDir:true HandleSegv:true Trace:false CallComments:true LegacyOptions:{Collide:false Fault:false FaultCall:0 FaultNth:0}}
r0 = syz_open_dev$ndb(&(0x7f0000000000), 0x0, 0xc0400)
r1 = syz_open_dev$ndb(&(0x7f0000000000), 0x0, 0x80040)
ioctl$NBD_SET_FLAGS(r1, 0xab0a, 0x9ad)
socketpair$nbd(0x1, 0x1, 0x0, &(0x7f0000000080)={<r2=>0xffffffffffffffff})
r3 = syz_open_dev$dri(&(0x7f0000000100), 0xfffffffffffffffc, 0xc8503)
r4 = syz_open_dev$ndb(&(0x7f0000000000), 0x0, 0xc0400)
socketpair$nbd(0x1, 0x1, 0x0, &(0x7f0000000080)={<r5=>0xffffffffffffffff})
ioctl$NBD_SET_SOCK(r4, 0xab00, r5)
r6 = syz_open_dev$ndb(&(0x7f0000000240), 0x0, 0x12100)
ioctl$NBD_DO_IT(r6, 0xab03)
close_range(r3, 0xffffffffffffffff, 0x0)
ioctl$NBD_SET_SIZE_BLOCKS(0xffffffffffffffff, 0xab07, 0x1)
ioctl$NBD_SET_SOCK(r0, 0xab00, r2)
r7 = syz_open_dev$loop(&(0x7f0000000040), 0x1, 0x200)
ioctl$BLKPG(r7, 0x1269, &(0x7f00000001c0)={0x1, 0x0, 0x98, &(0x7f00000000c0)={0x5, 0x2, 0x10}})
close(0x5)
r8 = syz_open_dev$ndb(&(0x7f0000000000), 0x0, 0x100)
r9 = syz_open_dev$ndb(&(0x7f0000000000), 0x0, 0xc0400)
socketpair$nbd(0x1, 0x1, 0x0, &(0x7f0000000080)={<r10=>0xffffffffffffffff})
ioctl$NBD_SET_SOCK(r9, 0xab00, r10)
close(0x5)
r11 = syz_open_dev$ndb(&(0x7f0000000000), 0x0, 0x100)
ioctl$NBD_DO_IT(r11, 0xab03)
r12 = syz_open_dev$ndb(&(0x7f0000000040), 0x0, 0x0)
ioctl$NBD_CLEAR_SOCK(r12, 0xab04)
ioctl$NBD_DO_IT(r8, 0xab03)
socket$inet6_tcp(0xa, 0x1, 0x0)
syz_open_dev$ndb(&(0x7f0000000000), 0x0, 0xc0400)




 block/blk-mq.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index d626d32f6e57..4357625a512d 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -4738,6 +4738,7 @@ static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
 				       int new_nr_hw_queues)
 {
 	struct blk_mq_tags **new_tags;
+	struct blk_mq_tags **old_tags;
 	int i;
 
 	if (set->nr_hw_queues >= new_nr_hw_queues)
@@ -4751,8 +4752,10 @@ static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
 	if (set->tags)
 		memcpy(new_tags, set->tags, set->nr_hw_queues *
 		       sizeof(*set->tags));
-	kfree(set->tags);
+	old_tags = set->tags;
 	set->tags = new_tags;
+	synchronize_srcu(&set->tags_srcu);
+	kfree(old_tags);
 
 	for (i = set->nr_hw_queues; i < new_nr_hw_queues; i++) {
 		if (!__blk_mq_alloc_map_and_rqs(set, i)) {

base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] block: blk-mq: fix UAF in blk_mq_tagset_busy_iter
  2026-04-30  4:28 [PATCH] block: blk-mq: fix UAF in blk_mq_tagset_busy_iter l1za0.sec
@ 2026-04-30 16:11 ` Bart Van Assche
  0 siblings, 0 replies; 2+ messages in thread
From: Bart Van Assche @ 2026-04-30 16:11 UTC (permalink / raw)
  To: l1za0.sec, axboe; +Cc: linux-block, linux-kernel


On 4/29/26 9:28 PM, l1za0.sec@gmail.com wrote:
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index d626d32f6e57..4357625a512d 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -4738,6 +4738,7 @@ static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
>   				       int new_nr_hw_queues)
>   {
>   	struct blk_mq_tags **new_tags;
> +	struct blk_mq_tags **old_tags;
>   	int i;
>   
>   	if (set->nr_hw_queues >= new_nr_hw_queues)
> @@ -4751,8 +4752,10 @@ static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
>   	if (set->tags)
>   		memcpy(new_tags, set->tags, set->nr_hw_queues *
>   		       sizeof(*set->tags));
> -	kfree(set->tags);
> +	old_tags = set->tags;
>   	set->tags = new_tags;
> +	synchronize_srcu(&set->tags_srcu);
> +	kfree(old_tags);
>   
>   	for (i = set->nr_hw_queues; i < new_nr_hw_queues; i++) {
>   		if (!__blk_mq_alloc_map_and_rqs(set, i)) {

The function blk_mq_realloc_tag_set_tags() no longer exists.

> base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449

That commit is too old. It's description is as follows: "Merge tag
'timers_urgent_for_v6.18_rc8' of git://git.kernel.org/pub/scm/linux/
kernel/git/tip/tip". Please develop block layer fixes against the
for-next branch of this kernel tree:
https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git/

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-04-30 16:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-30  4:28 [PATCH] block: blk-mq: fix UAF in blk_mq_tagset_busy_iter l1za0.sec
2026-04-30 16:11 ` Bart Van Assche

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox