CVE-2026-46051
Description
In the Linux kernel, the following vulnerability has been resolved:
md/raid5: fix soft lockup in retry_aligned_read()
When retry_aligned_read() encounters an overlapped stripe, it releases the stripe via raid5_release_stripe() which puts it on the lockless released_stripes llist. In the next raid5d loop iteration, release_stripe_list() drains the stripe onto handle_list (since STRIPE_HANDLE is set by the original IO), but retry_aligned_read() runs before handle_active_stripes() and removes the stripe from handle_list via find_get_stripe() -> list_del_init(). This prevents handle_stripe() from ever processing the stripe to resolve the overlap, causing an infinite loop and soft lockup.
Fix this by using __release_stripe() with temp_inactive_list instead of raid5_release_stripe() in the failure path, so the stripe does not go through the released_stripes llist. This allows raid5d to break out of its loop, and the overlap will be resolved when the stripe is eventually processed by handle_stripe().
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
md/raid5 in the Linux kernel has a soft lockup caused by an infinite loop in retry_aligned_read() when a released stripe bypasses the handle_stripe() path that would resolve overlap.
Vulnerability
In the Linux kernel's md/raid5 driver, the function retry_aligned_read() can trigger a soft lockup when it encounters an overlapped stripe. The bug was introduced in an unknown kernel version and is fixed in commit 1985cb3247e87ff6b8ca4bc5f9626f4f51024507. The affected code path involves releasing a stripe via raid5_release_stripe(), which places it on the lockless released_stripes llist. During the next raid5d loop iteration, release_stripe_list() drains the stripe onto handle_list (since STRIPE_HANDLE is set by the original IO). However, retry_aligned_read() runs before handle_active_stripes() and removes the stripe from handle_list via find_get_stripe() -> list_del_init(). This prevents handle_stripe() from ever processing the stripe to resolve the overlap, causing an infinite loop and soft lockup [1].
Exploitation
An attacker would need to trigger a specific I/O pattern that creates an overlapped stripe in the raid5 array and then causes retry_aligned_read() to encounter that stripe. The attack requires the ability to issue read requests to a Linux system using the md/raid5 driver. No special privileges or user interaction are needed beyond normal filesystem access; the attacker can cause the soft lockup by crafting or waiting for concurrent I/O that results in overlapping stripes [1].
Impact
Successful exploitation results in a soft lockup (denial of service) on the target system. The CPU core handling the raid5d kernel thread becomes stuck in an infinite loop, preventing further I/O processing and system responsiveness. The attacker does not gain code execution or data disclosure; the impact is limited to availability [1].
Mitigation
The fix is to use __release_stripe() with temp_inactive_list instead of raid5_release_stripe() in the failure path of retry_aligned_read(), so the stripe does not go through the released_stripes llist. This allows raid5d to break out of its loop, and the overlap will be resolved when the stripe is eventually processed by handle_stripe(). The fix is included in Linux kernel stable tree commits as of 27 May 2026 [1]. Users should apply kernel updates from their distribution that include commit 1985cb3247e87ff6b8ca4bc5f9626f4f51024507 or later. No workaround is available for unpatched systems [1].
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
107f9f7c697474md/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1f8360d4cdb774..6e79829c5acb67 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6641,7 +6641,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1f8360d4cdb774..6e79829c5acb67 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6641,7 +6641,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
09880592f5a9md/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index aad2b8c0c54180..6eb94e466f9042 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6691,7 +6691,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index aad2b8c0c54180..6eb94e466f9042 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6691,7 +6691,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
80fc6ca2cbdemd/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 5079943046743c..f71ed0f5382588 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6625,7 +6625,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 5079943046743c..f71ed0f5382588 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6625,7 +6625,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
1985cb3247e8md/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3b711a1198adbe..b9f0d01ce01cbc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6635,7 +6635,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3b711a1198adbe..b9f0d01ce01cbc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6635,7 +6635,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
883cc33b7af1md/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a8e8d431071bac..335d2b6b107969 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6641,7 +6641,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a8e8d431071bac..335d2b6b107969 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6641,7 +6641,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
09880592f5a9md/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index aad2b8c0c54180..6eb94e466f9042 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6691,7 +6691,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index aad2b8c0c54180..6eb94e466f9042 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6691,7 +6691,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
1985cb3247e8md/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3b711a1198adbe..b9f0d01ce01cbc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6635,7 +6635,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 3b711a1198adbe..b9f0d01ce01cbc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6635,7 +6635,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
80fc6ca2cbdemd/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 5079943046743c..f71ed0f5382588 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6625,7 +6625,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 5079943046743c..f71ed0f5382588 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6625,7 +6625,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
883cc33b7af1md/raid5: fix soft lockup in retry_aligned_read()
1 file changed · +7 −2
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a8e8d431071bac..335d2b6b107969 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6641,7 +6641,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
7f9f7c697474md/raid5: fix soft lockup in retry_aligned_read()
2 files changed · +14 −4
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1f8360d4cdb774..6e79829c5acb67 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6641,7 +6641,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
drivers/md/raid5.c+7 −2 modifieddiff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1f8360d4cdb774..6e79829c5acb67 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6641,7 +6641,13 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio, } if (!add_stripe_bio(sh, raid_bio, dd_idx, 0, 0)) { - raid5_release_stripe(sh); + int hash; + + spin_lock_irq(&conf->device_lock); + hash = sh->hash_lock_index; + __release_stripe(conf, sh, + &conf->temp_inactive_list[hash]); + spin_unlock_irq(&conf->device_lock); conf->retry_read_aligned = raid_bio; conf->retry_read_offset = scnt; return handled; -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Incorrect stripe release path in retry_aligned_read() creates an infinite scheduling loop that prevents handle_stripe() from resolving stripe overlap."
Attack vector
An attacker who can trigger aligned read I/O on a RAID5 array can cause a soft lockup. When `retry_aligned_read()` encounters an overlapped stripe, the old code released the stripe via `raid5_release_stripe()`, which put it on the lockless `released_stripes` llist. On the next `raid5d` loop iteration, `release_stripe_list()` moved the stripe onto `handle_list`, but `retry_aligned_read()` runs before `handle_active_stripes()` and removes the stripe from `handle_list` via `find_get_stripe()` -> `list_del_init()`. This prevents `handle_stripe()` from ever resolving the overlap, creating an infinite loop and soft lockup [patch_id=2660112]. No authentication or special privileges beyond the ability to issue I/O to the RAID5 device are required.
Affected code
The vulnerability is in the `retry_aligned_read()` function in `drivers/md/raid5.c` [patch_id=2660112]. When `add_stripe_bio()` fails due to an overlapped stripe, the original code called `raid5_release_stripe(sh)` which placed the stripe on the lockless `released_stripes` llist, causing a scheduling loop that prevents `handle_stripe()` from ever processing the overlap.
What the fix does
The patch replaces `raid5_release_stripe(sh)` with `__release_stripe(conf, sh, &conf->temp_inactive_list[hash])` inside a `spin_lock_irq`/`spin_unlock_irq` block [patch_id=2660112]. This bypasses the lockless `released_stripes` llist entirely, placing the stripe on `temp_inactive_list` instead. As a result, the stripe does not get re-queued onto `handle_list` during the same `raid5d` iteration, allowing `raid5d` to break out of its loop. The overlap will be resolved when the stripe is eventually processed by `handle_stripe()`.
Preconditions
- configThe system must have a RAID5 array configured and active.
- inputAn attacker must be able to issue aligned read I/O to the RAID5 device (no special privileges beyond I/O access).
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- git.kernel.org/stable/c/09880592f5a9dc73377d6eb5ac123537b5f8df49nvd
- git.kernel.org/stable/c/1985cb3247e87ff6b8ca4bc5f9626f4f51024507nvd
- git.kernel.org/stable/c/7f9f7c697474268d9ef9479df3ddfe7cdcfbbffcnvd
- git.kernel.org/stable/c/80fc6ca2cbde018d52e13f305edcd643911bd94bnvd
- git.kernel.org/stable/c/883cc33b7af1c448663287f069ef9dfea001e90fnvd
News mentions
0No linked articles in our index yet.