CVE-2026-45953
Description
In the Linux kernel, the following vulnerability has been resolved:
md/raid5: fix IO hang with degraded array with llbitmap
When llbitmap bit state is still unwritten, any new write should force rcw, as bitmap_ops->blocks_synced() is checked in handle_stripe_dirtying(). However, later the same check is missing in need_this_block(), causing stripe to deadloop during handling because handle_stripe() will decide to go to handle_stripe_fill(), meanwhile need_this_block() always return 0 and nothing is handled.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
In the Linux kernel md/raid5, a missing check in need_this_block() when using llbitmap with degraded arrays causes IO hang due to stripe deadloop.
Vulnerability
The vulnerability exists in the Linux kernel's md/raid5 module when using an llbitmap (log-likelihood bitmap). When a bitmap bit state is unwritten, the function handle_stripe_dirtying() correctly checks bitmap_ops->blocks_synced() to force an RCW (read-change-write) path. However, the same check is missing in need_this_block(), leading to a deadloop in stripe handling. handle_stripe() decides to proceed to handle_stripe_fill(), but need_this_block() always returns 0, causing no progress and an IO hang on degraded arrays. Affected versions are all Linux kernel versions before the fix commit [1].
Exploitation
An attacker must be able to write to a degraded RAID5 array that uses an llbitmap, with a bitmap bit state that is unwritten. No special privileges are required beyond normal write access. The attack sequence involves initiating a write operation to a stripe that has an unwritten bitmap bit while the array is degraded. This triggers the deadloop, resulting in an indefinite hang of I/O operations to that array.
Impact
Successful exploitation leads to an IO hang on the degraded RAID5 array, causing a denial of service (DoS) on the system. The system may become unresponsive as I/O operations stall indefinitely. This affects data availability and can disrupt system operation.
Mitigation
The issue is fixed by the Linux kernel commit [1] (commit hash cd1635d844d26471c56c0a432abdee12fc9ad735). Users should update their kernel to a version that includes this patch. No workarounds are mentioned in the available references. The CVE is not listed on the CISA Known Exploited Vulnerabilities (KEV) catalog.
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
6870b9f15867bmd/raid5: fix IO hang with degraded array with llbitmap
2 files changed · +12 −4
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1041788a54c20c..3b711a1198adbe 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1041788a54c20c..3b711a1198adbe 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
28ef299e7a5bmd/raid5: fix IO hang with degraded array with llbitmap
2 files changed · +12 −4
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a85878b009f9a4..bdf248db1330ae 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a85878b009f9a4..bdf248db1330ae 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
cd1635d844d2md/raid5: fix IO hang with degraded array with llbitmap
2 files changed · +12 −4
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6d408aaaacf37a..8854e024f3113b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6d408aaaacf37a..8854e024f3113b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
cd1635d844d2md/raid5: fix IO hang with degraded array with llbitmap
2 files changed · +12 −4
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6d408aaaacf37a..8854e024f3113b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6d408aaaacf37a..8854e024f3113b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
28ef299e7a5bmd/raid5: fix IO hang with degraded array with llbitmap
2 files changed · +12 −4
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a85878b009f9a4..bdf248db1330ae 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a85878b009f9a4..bdf248db1330ae 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
870b9f15867bmd/raid5: fix IO hang with degraded array with llbitmap
2 files changed · +12 −4
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1041788a54c20c..3b711a1198adbe 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
drivers/md/raid5.c+6 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1041788a54c20c..3b711a1198adbe 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3751,9 +3751,14 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, struct r5dev *dev = &sh->dev[disk_idx]; struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]], &sh->dev[s->failed_num[1]] }; + struct mddev *mddev = sh->raid_conf->mddev; + bool force_rcw = false; int i; - bool force_rcw = (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW); + if (sh->raid_conf->rmw_level == PARITY_DISABLE_RMW || + (mddev->bitmap_ops && mddev->bitmap_ops->blocks_synced && + !mddev->bitmap_ops->blocks_synced(mddev, sh->sector))) + force_rcw = true; if (test_bit(R5_LOCKED, &dev->flags) || test_bit(R5_UPTODATE, &dev->flags)) -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing check for llbitmap blocks_synced() in need_this_block() causes the function to always return 0 when the bitmap bit is unwritten, leading to a stripe deadloop."
Attack vector
An attacker with write access to a degraded RAID5 array that uses the llbitmap (lockless bitmap) can trigger an IO hang. When the llbitmap bit for a stripe is still in the "unwritten" state, any new write to that stripe should force a reconstruct-write (RCW) path. The check for bitmap_ops->blocks_synced() exists in handle_stripe_dirtying() but is missing in need_this_block() [patch_id=2661043]. This causes handle_stripe() to route to handle_stripe_fill(), while need_this_block() always returns 0, so no blocks are processed and the stripe deadloops indefinitely.
Affected code
The bug is in the need_this_block() function in drivers/md/raid5.c [patch_id=2661043]. The function previously only set force_rcw based on sh->raid_conf->rmw_level == PARITY_DISABLE_RMW, missing the llbitmap unwritten state check that was already present in handle_stripe_dirtying().
What the fix does
The patch adds the same bitmap_ops->blocks_synced() check that already exists in handle_stripe_dirtying() into need_this_block() [patch_id=2661043]. Specifically, it expands the force_rcw condition from only checking PARITY_DISABLE_RMW to also checking whether mddev->bitmap_ops->blocks_synced() returns false (meaning the bitmap bit is unwritten). When force_rcw is true, need_this_block() returns 1 for the block, allowing the stripe to make progress instead of deadlooping.
Preconditions
- configRAID5 array must be in degraded state (at least one failed disk)
- configArray must use the llbitmap (lockless bitmap) feature
- inputThe llbitmap bit for the target stripe must be in the unwritten state
- inputA write I/O must be issued to the affected stripe
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.