VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-46050

CVE-2026-46050

Description

In the Linux kernel, the following vulnerability has been resolved:

md/raid10: fix deadlock with check operation and nowait requests

When an array check is running it will raise the barrier at which point normal requests will become blocked and increment the nr_pending value to signal there is work pending inside of wait_barrier(). NOWAIT requests do not block and so will return immediately with an error, and additionally do not increment nr_pending in wait_barrier(). Upstream change commit 43806c3d5b9b ("raid10: cleanup memleak at raid10_make_request") added a call to raid_end_bio_io() to fix a memory leak when NOWAIT requests hit this condition. raid_end_bio_io() eventually calls allow_barrier() and it will unconditionally do an atomic_dec_and_test(&conf->nr_pending) even though the corresponding increment on nr_pending didn't happen in the NOWAIT case.

This can be easily seen by starting a check operation while an application is doing nowait IO on the same array. This results in a deadlocked state due to nr_pending value underflowing and so the md resync thread gets stuck waiting for nr_pending to == 0.

Output of r10conf state of the array when we hit this condition:

crash> struct r10conf barrier = 1, nr_pending = { counter = -41 }, nr_waiting = 15, nr_queued = 0,

Example of md_sync thread stuck waiting on raise_barrier() and other requests stuck in wait_barrier():

md1_resync [<0>] raise_barrier+0xce/0x1c0 [<0>] raid10_sync_request+0x1ca/0x1ed0 [<0>] md_do_sync+0x779/0x1110 [<0>] md_thread+0x90/0x160 [<0>] kthread+0xbe/0xf0 [<0>] ret_from_fork+0x34/0x50 [<0>] ret_from_fork_asm+0x1a/0x30

kworker/u1040:2+flush-253:4 [<0>] wait_barrier+0x1de/0x220 [<0>] regular_request_wait+0x30/0x180 [<0>] raid10_make_request+0x261/0x1000 [<0>] md_handle_request+0x13b/0x230 [<0>] __submit_bio+0x107/0x1f0 [<0>] submit_bio_noacct_nocheck+0x16f/0x390 [<0>] ext4_io_submit+0x24/0x40 [<0>] ext4_do_writepages+0x254/0xc80 [<0>] ext4_writepages+0x84/0x120 [<0>] do_writepages+0x7a/0x260 [<0>] __writeback_single_inode+0x3d/0x300 [<0>] writeback_sb_inodes+0x1dd/0x470 [<0>] __writeback_inodes_wb+0x4c/0xe0 [<0>] wb_writeback+0x18b/0x2d0 [<0>] wb_workfn+0x2a1/0x400 [<0>] process_one_work+0x149/0x330 [<0>] worker_thread+0x2d2/0x410 [<0>] kthread+0xbe/0xf0 [<0>] ret_from_fork+0x34/0x50 [<0>] ret_from_fork_asm+0x1a/0x30

Affected products

1

Patches

10
7d96f3120a7f

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index cfbd345805ca2d..4901ebe45c8755 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1184,7 +1184,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1372,7 +1372,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
965d6162dd88

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index 6bcf6852c20005..99aabf5734f5d9 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1204,7 +1204,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1425,7 +1425,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
42fe37c90184

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index db07c99c4d9470..4b02313854b67c 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1182,7 +1182,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1381,7 +1381,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
cac2106bb9a2

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index d58ae150b45022..706037d2a87c45 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1184,7 +1184,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1372,7 +1372,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
1cdff2937c61

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index 0653b5d8545a6c..12cbeec026c55c 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1184,7 +1184,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1372,7 +1372,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
1cdff2937c61

md/raid10: fix deadlock with check operation and nowait requests

2 files changed · +4 6
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index 0653b5d8545a6c..12cbeec026c55c 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1184,7 +1184,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1372,7 +1372,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index 0653b5d8545a6c..12cbeec026c55c 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1184,7 +1184,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1372,7 +1372,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
42fe37c90184

md/raid10: fix deadlock with check operation and nowait requests

2 files changed · +4 6
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index db07c99c4d9470..4b02313854b67c 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1182,7 +1182,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1381,7 +1381,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index db07c99c4d9470..4b02313854b67c 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1182,7 +1182,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1381,7 +1381,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
7d96f3120a7f

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index cfbd345805ca2d..4901ebe45c8755 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1184,7 +1184,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1372,7 +1372,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
965d6162dd88

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index 6bcf6852c20005..99aabf5734f5d9 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1204,7 +1204,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1425,7 +1425,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    
cac2106bb9a2

md/raid10: fix deadlock with check operation and nowait requests

1 file changed · +2 3
  • drivers/md/raid10.c+2 3 modified
    diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
    index d58ae150b45022..706037d2a87c45 100644
    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1184,7 +1184,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
     	}
     
     	if (!regular_request_wait(mddev, conf, bio, r10_bio->sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    @@ -1372,7 +1372,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
     
     	sectors = r10_bio->sectors;
     	if (!regular_request_wait(mddev, conf, bio, sectors)) {
    -		raid_end_bio_io(r10_bio);
    +		free_r10bio(r10_bio);
     		return;
     	}
     
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing accounting for NOWAIT requests in the barrier mechanism: `raid_end_bio_io()` unconditionally decrements `nr_pending` via `allow_barrier()`, but NOWAIT requests never incremented `nr_pending` in `wait_barrier()`, causing an underflow that deadlocks the resync thread."

Attack vector

An attacker or local user triggers a RAID10 array check operation (e.g. via `mdadm --check`) while simultaneously issuing NOWAIT I/O requests to the same array. The check raises the barrier, causing normal requests to block and increment `nr_pending`. NOWAIT requests return immediately without incrementing `nr_pending`, but the code path introduced by commit 43806c3d5b9b calls `raid_end_bio_io()` which unconditionally decrements `nr_pending` via `allow_barrier()`. This mismatch causes `nr_pending` to underflow (observed value -41), preventing the resync thread from ever seeing `nr_pending == 0`, resulting in a permanent deadlock of the md resync thread and all subsequent I/O [patch_id=2660129].

Affected code

The bug is in `drivers/md/raid10.c` in the functions `raid10_read_request()` and `raid10_write_request()` [patch_id=2660129]. When `regular_request_wait()` returns false for a NOWAIT bio, the code previously called `raid_end_bio_io(r10_bio)` which eventually calls `allow_barrier()` and unconditionally decrements `conf->nr_pending`. The fix changes these calls to `free_r10bio(r10_bio)` instead.

What the fix does

The patch replaces `raid_end_bio_io(r10_bio)` with `free_r10bio(r10_bio)` in both `raid10_read_request()` and `raid10_write_request()` when `regular_request_wait()` fails for a NOWAIT request [patch_id=2660129]. `raid_end_bio_io()` calls `allow_barrier()` which unconditionally decrements `conf->nr_pending`, but NOWAIT requests never incremented that counter. By using `free_r10bio()` instead, the bio is freed without touching the barrier accounting, preventing the `nr_pending` underflow that caused the deadlock. The memory leak that commit 43806c3d5b9b originally fixed is still addressed because `free_r10bio()` properly releases the `r10_bio` structure.

Preconditions

  • configA RAID10 array must be configured and active on the system.
  • inputAn application must issue NOWAIT I/O requests (REQ_NOWAIT) to the RAID10 array.
  • inputA check operation (e.g. via mdadm --check) must be started on the same array while NOWAIT I/O is in flight.

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.