summaryrefslogtreecommitdiff
path: root/drivers/md
AgeCommit message (Collapse)AuthorFilesLines
2026-08-04dm array: reject an array block whose value size is not the caller'sBryam Vargas1-0/+16
array_block_check() can only compare the header against itself, so a block with value_size 4 and max_entries 1018 is internally consistent and passes. dm-cache keeps two arrays -- mappings at 8 bytes and hints at 4 -- and the roots for both live in the superblock. Point the mappings root at a hint block and __load_mappings() walks it through an info whose value size is 8, so element_at() strides 8 bytes over 4-byte entries and reaches offset 8160 of a 4096-byte block. get_ablock() and __shadow_ablock() are the two places that hold the block and the caller at once. Reject there when the two value sizes disagree. Arrays only ever read their own blocks, so this fires on crafted metadata only. Fixes: 6513c29f44f2 ("dm persistent data: add transactional array") Suggested-by: Ming-Hung Tsai <mtsai@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Reviewed-by: Ming-Hung Tsai <mtsai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-08-04dm array: validate array block headers on readBryam Vargas1-8/+29
array_block_check() validates blocknr and csum and nothing else, while node_check(), next to it, has bounded the structural fields since both were written. dm_array_cursor_next() takes its loop bound from the on-disk nr_entries and element_at() is unguarded pointer arithmetic, so a count larger than the block holds keeps the cursor in one block while the index grows past it and the read walks off the dm-bufio buffer -- dm_cache_load_mappings() drives it once per cache block at activation. Check the header against itself: reject a zero value_size, require max_entries to equal calc_max_entries() for that value_size and block size, and require nr_entries to fit. Equality rather than an upper bound, since a count below the real capacity trips BUG_ON() in fill_ablock() and trim_ablock(). Metadata dm-array writes satisfies all three. Fixes: 6513c29f44f2 ("dm persistent data: add transactional array") Suggested-by: Ming-Hung Tsai <mtsai@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Reviewed-by: Ming-Hung Tsai <mtsai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-08-03dm-integrity: replace forgeable discard filler with a keyed sector markerShukai Ni1-22/+115
The discard-block check in dm_integrity_rw_tag() treats a stored tag of all 0xf6 bytes (DISCARD_FILLER) as proof a block was discarded and skips HMAC verification. allow_discards is only accepted in dm-integrity's standalone mode. An attacker with raw write access to the backing device, but without the integrity key, can stamp any block with an all-0xf6 tag and have it served as authentic. Add a new "allow_discards_keyed" target argument that marks discarded blocks with a keyed checksum of (salt || sector) instead, computed by integrity_discard_checksum(). Fixes: 84597a44a9d8 ("dm integrity: add optional discard support") Co-developed-by: Jo Van Bulck <jo.vanbulck@cs.kuleuven.be> Signed-off-by: Jo Van Bulck <jo.vanbulck@cs.kuleuven.be> Signed-off-by: Shukai Ni <shukai.ni@kuleuven.be> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-31md/raid1: create serial pool adding rdev to array with serialize_policy=1Martin Wilck1-1/+2
The following bug has been observed with kernel 7.1.3 after adding a new rdev to an existing RAID1 array with serialize_policy enabled: Oops: 0002 [#1] CPU: 0 UID: 0 PID: 19639 Comm: ext4lazyinit Not tainted 7.1.3-1-default RIP: _raw_spin_lock_irqsave+0x27/0x50 CR2: 0000000000004960 Call Trace: wait_for_serialization+0xb9/0x260 [raid1] raid1_make_request+0x762/0xaff [raid1] md_handle_request+0x1c9/0x2e0 [md_mod] The raid1.c code calls wait_for_serialization() if the MD_SERIALIZE_POLICY is set, and wait_for_serialization assumes that rdev->serial is initialized. Normally this will be the case for arrays that have the serialize_policy sysfs attribute set to 1. But when a new rdev is added to an existing array in bind_rdev_to_array(), the condition at mddev_create_serial_pool() causes creation of rdev->serial to be skipped. Fix it. Fixes: 69b00b5bb235 ("md: introduce a new struct for IO serialization") Signed-off-by: Martin Wilck <mwilck@suse.com> Reviewed-by: Mykola Marzhan <mykola@meshstor.io> Link: https://patch.msgid.link/20260723112741.1206836-1-mwilck@suse.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md: do overflow check for sb->bblog_shift in super_1_load()Coly Li1-0/+7
In super_1_load(), sb->bblog_shift is an __u8 type value loaded from on- disk superblock. It is used for badblocks API badblocks_set() by the following sequence, 1930 rdev->badblocks.shift = sb->bblog_shift; 1931 for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) { 1932 u64 bb = le64_to_cpu(*bbp); 1933 int count = bb & (0x3ff); 1934 u64 sector = bb >> 10; 1935 sector <<= sb->bblog_shift; 1936 count <<= sb->bblog_shift; 1937 if (bb + 1 == 0) 1938 break; 1939 if (!badblocks_set(&rdev->badblocks, sector, count, 1)) 1940 return -EINVAL; 1941 } bb->bblog_shit is in range of 0-255, variable sector is 64bit width, for an invalid bb->bblog_shit, it is possible to make sector be overflowed by the following calculation, 1935 sector <<= sb->bblog_shift; Then in turn when call badblocks_set() at line 1939 with the invalid rdev->badblocks.shift set at line 1930, may result an overflow inside _badblocks_clear() in block/badblocks.c. Although there are many places to call badblocks APIs, the non-zero shift value is only used in super_1_load(), other places always use 0 as the shift value. Therefore it is unnecessary to do a general shift value overflow check inside badblock API, and just check here as the caller. This may avoid unnecessary check, make the badblocks API code more simple and elegant. Fixes: 2699b67223ac ("md: load/store badblock list from v1.x metadata") Fixes: 1726c7746783 ("badblocks: improve badblocks_set() for multiple ranges handling") Cc: stable@vger.kernel.org Cc: Ramesh Adhikari <adhikari.resume@gmail.com> Signed-off-by: Coly Li <colyli@fygo.io> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260720111400.2120834-1-colyli@fygo.io Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md: scope memalloc_noio to allocation critical sectionsChen Cheng4-23/+48
Storing a memalloc_noio_save() token in mddev->noio_flags lets one task save the token and another task restore it. With concurrent suspend sysfs writes, task A can enter PF_MEMALLOC_NOIO, return to userspace still in that scope, and later task B can restore A's saved token. Avoid tying the token lifetime to mddev. Keep mddev_suspend() and mddev_resume() only responsible for array suspension, and enter PF_MEMALLOC_NOIO only in the MD paths that allocate memory after the array has been suspended. Restore the token before resuming the array. A reproducer repeatedly writes suspend_lo and suspend_hi from concurrent workers and checks each worker's /proc/self/stat flags before and after the sysfs write. Link: https://github.com/chencheng-fnnas/reproducer/blob/main/repro-md-noio-token-leak.sh Fixes: 78f57ef9d50a ("md: use memalloc scope APIs in mddev_suspend()/mddev_resume()") Signed-off-by: Chen Cheng <chencheng@fnnas.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260718084218.417895-1-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md/bitmap: resume array on backlog_store() error pathChen Cheng1-1/+1
backlog_store() suspends the array before checking whether a write-mostly device exists. If no such device exists, the error path only unlocks reconfig_mutex and leaves the array suspended, blocking subsequent I/O. Use mddev_unlock_and_resume() to release both states. Fixes: 58226942ad3d ("md: use new apis to suspend array before mddev_create/destroy_serial_pool") Signed-off-by: Chen Cheng <chencheng@fnnas.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260718034236.4119093-1-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md/raid5: complete discard bios while reshape is activeGenjian Zhang1-2/+6
make_discard_request() returns without completing the bio when reshape is in progress. Discard callers block in submit_bio_wait() waiting for a completion that never arrives. The caller hangs in uninterruptible sleep, and this does not resolve when reshape finishes. Complete the bio with BLK_STS_AGAIN so userspace can retry after reshape, consistent with the existing policy of not processing discard during reshape. Tested on a loop-backed RAID5 array during mdadm --grow: without this patch, blkdiscard hangs in bio_await() and remains in uninterruptible sleep after md reports "reshape done"; with this patch it returns -EAGAIN instead. Signed-off-by: Genjian Zhang <zhanggenjian@kylinos.cn> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260711161326.962336-1-zhanggenjian@126.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md/raid10: free r10bio before ending master_bio in raid_end_bio_io() and ↵Chen Cheng1-4/+10
raid_end_discard_bio() origin flow: bio_endio(master_bio); /* may drop active_io to zero */ allow_barrier(conf); free_r10bio(r10_bio); /* reads conf->geo, returns to pool */ one scenario is: CPU A (softirq, raid_end_bio_io) CPU B (action_store) --> reshape ================================ =============================== bio_endio(master_bio) md_end_clone_io percpu_ref_put -> 0 wait_event wakeup, and, mddev_suspend return raid10_start_reshape: setup_geo(&conf->geo, new) ... mempool_destroy(old_pool) conf->r10bio_pool = new_pool allow_barrier(conf) free_r10bio(r10_bio) put_all_bios: for (i=0; i<conf->geo.raid_disks; i++) ==> old obj, new geo, OOB mempool_free(r10_bio, conf->r10bio_pool) ==> old-geometry obj freed into new pool so .. fix by reorder the flow: free_r10bio(r10_bio) bio_endio(master_bio) allow_barrier(conf) raid_end_discard_bio() is exactly the same. Signed-off-by: Chen Cheng <chencheng@fnnas.com> Link: https://patch.msgid.link/20260711100352.425177-4-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md/raid10: resize r10bio_pool for reshapeChen Cheng2-14/+34
When reshape grows raid_disks, the pool must also switch to new geometry object size , and allocate a new geometry size pool and replace the old. But not for shrinking reshape, because regular I/O can still use the prev geo for sectors that have not crossed reshape_progress yet. Signed-off-by: Chen Cheng <chencheng@fnnas.com> Link: https://patch.msgid.link/20260711100352.425177-3-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md: suspend array when sync_action=reshapeChen Cheng1-3/+12
raid10 needs to resize/swap r10bio_pool when reshape changes raid_disks, and, don't let new requests keep allocating r10bio objects from the old pool while that transition is in progress. suspend and lock array before mddev_start_reshape(), and resume it on exit. Other sync_action ops are unchanged. Signed-off-by: Chen Cheng <chencheng@fnnas.com> Link: https://patch.msgid.link/20260711100352.425177-2-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-31md: widen badblock sectors param from int to sector_tHiroshi Nishida2-5/+5
The badblocks core API -- badblocks_set(), badblocks_clear() and badblocks_check() -- and the is_badblock() helper all take the range length as sector_t. The md wrappers rdev_set_badblocks(), rdev_clear_badblocks() and rdev_has_badblock(), however, declared the same length as int, narrowing sector_t to int and back again in the middle of an otherwise 64-bit clean path. Change the sectors parameter to sector_t in these three wrappers so it matches the core API and is_badblock(). No functional change: current callers pass per-I/O or per-resync-chunk lengths well within int range. This just removes a gratuitous truncation point and keeps the type consistent end to end. Signed-off-by: Hiroshi Nishida <nishidafmly@gmail.com> Link: https://patch.msgid.link/20260710132329.7273-3-nishidafmly@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid10: remove unnecessary barrier around bio_submit_split_bioset()Abd-Alrhman Masalkhi1-2/+0
raid10_write_request() drops the barrier before calling bio_submit_split_bioset() and reacquires it afterwards. This is no longer necessary because the split bio cannot re-enter raid10_write_request() while the barrier is held. The allow_barrier()/wait_barrier() pair was introduced by commit e820d55cb99d ("md: fix raid10 hang issue caused by barrier") when submit_flushes() called md_handle_request() directly, allowing re-entry into raid10_write_request(). Since v5.2, submit_flushes() has instead gone through submit_bio(), eliminating that recursion. submit_flushes() was later removed entirely by commit b75197e86e6d ("md: Remove flush handling"). Currently, raid10_write_request() is only entered from the bio submission path, so the split bio submitted by bio_submit_split_bioset() cannot recurse back into wait_barrier(). Remove the redundant allow_barrier()/wait_barrier() pair around bio_submit_split_bioset(). Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260710101521.1714-5-abd.masalkhi@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid10: consistently fail atomic writes that require splittingAbd-Alrhman Masalkhi1-10/+4
RAID10 currently handles one badblock path explicitly by failing atomic writes with EIO. However, another badblock path can also reduce the writable range and force the bio through bio_submit_split_bioset(), which implicitly completes the bio with EINVAL. Fix this by handling atomic writes in the common split check. If RAID10 determines that an atomic write would require splitting, complete the bio with EIO. Fixes: a1d9b4fd42d9 ("md/raid10: Atomic write support") Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Reviewed-by: John Garry <john.g.garry@oracle.com> Link: https://patch.msgid.link/20260710101521.1714-4-abd.masalkhi@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid1: restrict atomic write limits and handle runtime constraintsAbd-Alrhman Masalkhi1-13/+9
Restrict the RAID1 atomic write limits by setting chunk_sectors to BARRIER_UNIT_SECTOR_SIZE so that atomic writes never straddle a barrier unit. A bio that passes block-layer validation may still become unserviceable within RAID1 due to bad blocks or write-behind constraints. In the former case, complete the bio with EIO. In the latter case, disable write-behind rather than failing the bio with EIO. Fixes: f2a38abf5f1c ("md/raid1: Atomic write support") Fixes: a4c55c902670 ("md/raid1: simplify raid1_write_request() error handling") Reviewed-by: John Garry <john.g.garry@oracle.com> Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260710101521.1714-3-abd.masalkhi@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md: recheck spare changes before starting syncAbd-Alrhman Masalkhi1-1/+13
remove_spares() and remove_and_add_spares() modify the array's rdev configuration. These operations are only safe after the array has been suspended. md_start_sync() checks whether spare configuration changes are needed before taking reconfig_mutex. However, the rdev state can change before the mutex is acquired, so the initial check can become stale. In that case, md_choose_sync_action() may remove or replace rdevs while normal I/O is still accessing them. The race can occur as follows: raid10d Worker Normal IO ____________ _______________________ ______________________ raid10_write_request() wait_blocked_dev() set Blocked set Faulty Skip Faulty rdev rrdev->nr_pending++ .repl_bio = bio removeable_rdev = false . array not suspended . lock mddev goto err_handle lock mddev (wait) . update sb . clear Blocked . . unlock mddev . lock mddev (acquires) remove_spares() removeable_rdev = true raid10_remove_disk() rdev = replacement replacement = NULL rdev_dec_pending(NULL) unlock mddev (NULL)->nr_pending-- In this case, rdev_dec_pending() is called with a NULL pointer, resulting in a NULL pointer dereference when attempting to decrement nr_pending. Fix this by suspending the array when spare configuration changes are needed, including for non-read-write arrays, and checking again after taking reconfig_mutex. If the array was not already suspended and a change is now needed, release the mutex, suspend the array, and reacquire the mutex before continuing. Fixes: bc08041b32ab ("md: suspend array in md_start_sync() if array need reconfiguration") Reported-by: sashiko-bot <sashiko-bot@kernel.org> Closes: https://sashiko.dev/#/patchset/20260628142420.1051027-1-abd.masalkhi@gmail.com?part=3 Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260708112003.474537-1-abd.masalkhi@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md: remove REQ_NOWAIT support from raid1/10/456Abd-Alrhman Masalkhi10-185/+60
REQ_NOWAIT support in md personalities that can block internally is fundamentally incomplete. While reads can avoid some blocking paths, write requests can still encounter cases where one mirror succeeds while another returns -EAGAIN. At that point md cannot distinguish queue pressure from a real device failure, so it can neither record a bad block nor safely retry the write without REQ_NOWAIT, leaving mirrors with divergent data. Rather than continue advertising REQ_NOWAIT support for personalities that cannot implement it correctly, remove it from raid1, raid10 and raid456. Keep REQ_NOWAIT for linear and raid0, which only remap bios to their underlying devices; stacked limits will still clear the feature if any component device lacks REQ_NOWAIT support. Fixes: bf2c411bb1cf ("md: raid456 add nowait support") Fixes: c9aa889b035f ("md: raid10 add nowait support") Fixes: 5aa705039c4f ("md: raid1 add nowait support") Fixes: f51d46d0e7cb ("md: add support for REQ_NOWAIT") Suggested-by: Yu Kuai <yukuai@fygo.io> Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260628142737.1051059-1-abd.masalkhi@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid5: protect lockless recovery_offset accesses during reshapeChen Cheng1-25/+25
During reshape: - reshape_request() advances rdev->recovery_offset for non-In_sync devices locklessly. - analyse_stripe() reads rdev->recovery_offset locklessly to decide: a. use a replacement device to read ? b. a device can already be treated as in-sync for the current stripe ? one possible scenario is: CPU1 CPU2 reshape_request() -> mddev->curr_resync_completed = sector_nr -> if (!mddev->reshape_backwards) -> rdev->recovery_offset = sector_nr analyse_stripe(sh) -> rdev = conf->disks[i].replacement -> if (rdev->recovery_offset >= sh->sector + stripe_sectors) set_bit(R5_ReadRepl) -> or -> if (sh->sector + stripe_sectors <= rdev->recovery_offset) set_bit(R5_Insync) And it could be: - reading from a replacement before it is recovered far enough; or - treating a not-yet-recovered device as in-sync for the current stripe. Fixes: db0505d32066 ("md: be cautious about using ->curr_resync_completed for ->recovery_offset") The race report: ================================================================== BUG: KCSAN: data-race in ops_run_io / reshape_request write to 0xffff8bdee168b270 of 8 bytes by task 1704 on cpu 10: reshape_request+0x1292/0x17b0 raid5_sync_request+0x815/0xa00 md_do_sync.cold+0xf8d/0x1516 [......] read to 0xffff8bdee168b270 of 8 bytes by task 1696 on cpu 9: ops_run_io+0xc25/0x1960 handle_stripe+0x2273/0x4570 handle_active_stripes.isra.0+0x6e0/0xa50 raid5d+0x7d5/0xb90 [......] value changed: 0x0000000000091a00 -> 0x0000000000091b00 ================================================================== Signed-off-by: Chen Cheng <chencheng@fnnas.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260627102519.136940-1-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid5: fix reshape deadlock while failed devices more than max degradedChen Cheng1-0/+75
reshape stripe lifetime: - start reshape ==> reshape_request(): * get destination stripe, - if need to copy source data chunks, set STRIPE_EXPANDING; - or, if new regions past the old end of the array, zero-filled, no need source data, set STRIPE_EXPANDING | STRIPE_READY * get source stripe, - set STRIPE_EXPAND_SOURCE - handle expand stripe ==> handle_stripe(): reshape use reconstruct-write to construct stripe, four stages: 1. prepare source data chunks for old geometry stripe - fill source stripe data by read or compute 2. move data from old geometry source stripe to new geometry destination stripe - source stripe clear STRIPE_EXPAND_SOURCE - drain data from source to destination stripe - mark stripe chunk as R5_Expanded|R5_UPTODATE when the drain from source chunk to destination chunk is completed - all stripe chunks drain are completed, then mark STRIPE_EXPAND_READY 3. calculate p/q chunks for destination stripe - if destination stripe doesn't depends on source dstripe, then we can clear STRIPE_EXPANDING 4. write-out to disks and release - set R5_Wantwrite|R5_Locked, writeout to disk - if write-out succeeded, clear STRIPE_EXPAND_READY, and decrement reshape_stripe, call md_done_sync() to report reshape progress. 1. cleanup the following kinds of **destination stripe** when failed device more than max degraded: - new regions past the old end of the array, zero-filled in place, requires no source data. (STRIPE_EXPANDING | STRIPE_EXPAND_READY) - prepare source data chunks already done, and writeout failed (STRIPE_EXPAND_READY) 2. destination stripes that need source data (STRIPE_EXPANDING, no STRIPE_HANDLE) - these kind of stripes sit idle in the stripe cache and are never seen by handle_stripe(). So clean up indirectly when their source stripe (type 3) is processed. 3. source stripes (STRIPE_EXPAND_SOURCE) - hit handle_stripe() after their member disks are marked Faulty. - clear STRIPE_EXPAND_SOURCE, finds and cleanup all dependent destination stripes that were waiting for data. - walks the source's data disks, compute the corresponding destination sector, looks up the destination stripe, and do cleanup(clear flags, dec counters, call md_done_sync()) Reproducer: - Create a 4-disk RAID5 with mdadm on top of 5 disposable test disks wrapped by dm targets. - Add the 5th device as a spare and start a 4 -> 5 reshape. - Wait until /sys/block/mdX/md/sync_action reports "reshape". - Inject failures on two members so reshape exceeds max_degraded. - After a few seconds, write "frozen" to /sys/block/mdX/md/sync_action. Before this fix, the write blocks indefinitely. Read-error variant: - Use dm-dust on /dev/sd[b-f]. - Preload bad blocks on two source members, e.g. dust0 and dust1: dmsetup message dust0 0 addbadblock <range> dmsetup message dust1 0 addbadblock <range> - Start reshape: mdadm -C /dev/mdX -e 1.2 -l 5 -n 4 -c 64 \ --assume-clean /dev/mapper/dust{0..3} mdadm --manage /dev/mdX --add /dev/mapper/dust4 mdadm --grow /dev/mdX -n 5 --backup-file=/tmp/grow.backup & - Once reshape starts, enable the injected read failures: dmsetup message dust0 0 enable dmsetup message dust1 0 enable - Then: echo frozen > /sys/block/mdX/md/sync_action hangs forever before the fix. Write-error variant: - Use dm-flakey on /dev/sd[b-f]. - Start the same 4 -> 5 reshape on flakey0..flakey4. - Once reshape starts, switch two members, e.g. flakey3 and flakey4, to error_writes. - Then: echo frozen > /sys/block/mdX/md/sync_action hangs forever before the fix. md_do_sync() exits its main loop on MD_RECOVERY_INTR but then blocks forever at: wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active)); After the fix recovery_active drains to zero, md_do_sync() prints md/raid:md0: Cannot continue operation (2/5 failed). md: md0: reshape interrupted. Signed-off-by: Chen Cheng <chencheng@fnnas.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260624075824.2601110-1-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid5: fix lockless max_nr_stripes readsChen Cheng1-4/+4
max_nr_stripes is updated under cache_size_mutex in the stripe cache grow/shrink paths, while is_inactive_blocked() and raid5_end_read_request() read it without that lock. Use READ_ONCE() for those reads in lockless path to match the WRITE_ONCE() updates and avoid KCSAN data race reports. A similar issue was previously fixed in commit-id: dfd2bf436709b2bccb78c2dda550dde93700efa7. Fixes: 0009fad03337 ("raid5 improve too many read errors msg by adding limits") Fixes: 3514da58be9c ("md/raid5: Make is_inactive_blocked() helper") KCSAN report: ================= BUG: KCSAN: data-race in grow_one_stripe / is_inactive_blocked write (marked) to 0xffff8f01f0b5a268 of 4 bytes by task 12616 on cpu 9: grow_one_stripe+0x2d8/0x320 raid5d+0xb57/0xba0 md_thread+0x15a/0x2d0 [..........] read to 0xffff8f01f0b5a268 of 4 bytes by task 12670 on cpu 11: is_inactive_blocked+0x97/0xc0 raid5_get_active_stripe+0x2fd/0xa70 raid5_make_request+0x4aa/0x2940 [..........] value changed: 0x000003b9 -> 0x000003ba Signed-off-by: Chen Cheng <chencheng@fnnas.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260624024042.2561803-1-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid1: protect sequential read hints for read balanceChen Cheng1-8/+10
The patch just suppress KCSAN noise. No functional change. KCSAN reports a race, point to update_read_sectors() update next_seq_sect vs. read next_seq_sect. Protect next_seq_sect and seq_start with READ_ONCE/WRITE_ONCE, otherwise, read balance see stale sequential-read hints. KCSAN report: ============== BUG: KCSAN: data-race in raid1_read_request / raid1_read_request write to 0xffff8e3a2d6736d0 of 8 bytes by task 593784 on cpu 10: raid1_read_request+0xe5a/0x19f0 raid1_make_request+0xdf/0x1990 md_handle_request+0x4a2/0xa40 [...] read to 0xffff8e3a2d6736d0 of 8 bytes by task 593776 on cpu 11: raid1_read_request+0xe3f/0x19f0 raid1_make_request+0xdf/0x1990 md_handle_request+0x4a2/0xa40 [...] value changed: 0x0000000000356368 -> 0x0000000000356370 Signed-off-by: Chen Cheng <chencheng@fnnas.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260623075940.2476255-1-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid5-ppl: fix use-after-free in ppl_do_flush()Sajal Gupta1-1/+3
The loop in ppl_do_flush() continues iterating after calling ppl_io_unit_finished(), touching io->pending_flushes and leading to a use-after-free. Add a break statement to stop the loop once io is freed. Fixes: 1532d9e87e8b ("raid5-ppl: PPL support for disks with write-back cache enabled") Reported-by: Dan Carpenter <error27@gmail.com> Closes: https://lore.kernel.org/all/ajJF2wKYWRk4GGCK@stanley.mountain/ Signed-off-by: Sajal Gupta <sajal2005gupta@gmail.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260622142146.56637-1-sajal2005gupta@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-30md/raid5: protect bitmap batch counters aka seq_flush/seq_write consistencyChen Cheng1-4/+6
kcsan detect race : - raid5d() closes the current bitmap batch by updating conf->seq_flush under conf->device_lock. - __add_stripe_bio() read conf->seq_flush without that lock when assigning sh->bm_seq. so, protect seq_flush/seq_write consistency for multiple CPUs by READ_ONCE()/WRITE_ONCE() under the path without held device_lock. re-explain the stripe batch sequence number update flow: 1. sh->bm_seq declare which batch number the stripe belongs to when perform bitmap-related write. ==> bm_seq = seq_flush+1 2. stripe be handled, * if sh->bm_seq - conf->seq_write > 0, means the batch stripes **newer than** the last written batch, it cannot proceed yet, queued on bitmap_list. * otherwise , has already proceed. 3. raid5d() `++seq_flush` to closes the current batch, means * no more stripes join that old batch * just-closed batch ready to write-out to disk 4. raid5d() calls bitmap hooks unplug() or writeout, then, `++seq_write` to the same as bm_seq. - seq_flush - for producer, to close batches. - seq_write - for consumer, the checkpoint number. the report: ==================================== BUG: KCSAN: data-race in __add_stripe_bio / raid5d write to 0xffff88ba5625d470 of 4 bytes by task 82401 on cpu 0: raid5d+0x1d9/0xba0 [.....] read to 0xffff88ba5625d470 of 4 bytes by task 82421 on cpu 8: __add_stripe_bio+0x332/0x400 raid5_make_request+0x6ac/0x2930 md_handle_request+0x4a2/0xa40 md_submit_bio+0x109/0x1a0 __submit_bio+0x2ec/0x390 [.....] Fixes: 7c13edc87510 ("md: incorporate new plugging into raid5.") v1 -> v2: - remove WRITE_ONCE(conf->seq_write) in held device_lock path. - remove READ_ONCE(conf->seq_flush) in held device_lock path. Signed-off-by: Chen Cheng <chencheng@fnnas.com> Reviewed-by: Yu Kuai <yukuai@fygo.io> Link: https://patch.msgid.link/20260622124649.1780233-1-chencheng@fnnas.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
2026-07-28dm vdo indexer: embed geometry in parent structurescorwin11-149/+108
Embed struct index_geometry in struct uds_configuration and struct volume directly, eliminating the need to allocate (and free) the geometry separately. Signed-off-by: corwin <corwincoburn@google.com> Signed-off-by: Matthew Sakai <msakai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-28dm vdo indexer: simplify sub-index parameter calculationscorwin1-95/+93
Pull the calculations from split_config() into compute_volume_sub_index_parameters(). For sparse indexes, this eliminates the duplication of both the configs and geometries in favor of merely having 2 sub_index_parameters structures. Also expand the sub_index_parameters structure to include the small number of fields its users rely on from both the config and the geometry. Signed-off-by: corwin <corwincoburn@google.com> Signed-off-by: Matthew Sakai <msakai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-28dm-pcache: remove unused 'cache' parameter from cache_key_gc()Jianyun Gao1-3/+2
The 'cache' parameter is never used in the function body, remove it. Signed-off-by: Jianyun Gao <jianyungao89@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-28dm-pcache: remove unused miss_read_end_work_fn declarationJianyun Gao1-1/+0
This function is declared but never defined or called anywhere. The miss read completion is handled via miss_read_end_req callback instead. Remove the orphan declaration. Signed-off-by: Jianyun Gao <jianyungao89@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-27dm-io: report non-retryable errors separatedlyMikulas Patocka9-51/+80
The error codes BLK_STS_NOTSUPP and BLK_STS_INVAL should not cause leg failure on dm-raid1. This patch changes the interface to dm-io, so that it reports two error bitmaps - error_bits and unsup_bits. The unsup_bit bitmap tracks BLK_STS_NOTSUPP or BLK_STS_INVAL errors, the error_bits bitmap tracks all the other errors. dm-raid1 is changed so that it won't fail a leg if it receives an error in the unsup_bits bitmap. This patch (with 62dc37a819a5) fixes misbehavior if the user uses unaligned bio vectors on dm-raid1. Fixes: 7eac33186957 ("iomap: simplify direct io validity check") Fixes: 5ff3f74e145a ("block: simplify direct io validity check") Cc: stable@vger.kernel.org Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-27dm-io: clone the source bio instead of copying its biovecKeith Busch1-43/+24
For DM_IO_BIO requests, do_region() built each destination bio by walking the source bio's biovec and re-adding the pages one at a time, tracking the remaining transfer in sectors. The vector lengths are byte granular and need not be sector aligned (e.g. a misaligned O_DIRECT buffer split across pages), so the sector-based accounting could lose a sub-sector fragment: to_sector() truncated the remainder and the outer loop spun forever submitting empty bios, hanging the I/O. There is no need to rebuild the biovec at all. The destination reads into (or writes from) exactly the same pages as the source bio, so the bio can simply clone the source's biovec with bio_alloc_clone() and remap it to the target device. The clone inherits the source's iterator and alignment, and the block layer splits it to the target's limits on submission, so the whole region maps to a single cloned bio with no manual page copying or sector accounting. This removes the per-page copy path (and its open-coded bvec dpages helpers) for bio-backed I/O and fixes the hang on misaligned direct I/O to a dm-mirror device. Page-list, vma and kmem sources keep the existing copy path. Fixes: 7eac33186957 ("iomap: simplify direct io validity check") Fixes: 5ff3f74e145a ("block: simplify direct io validity check") Cc: stable@vger.kernel.org Reported-by: Dr. David Alan Gilbert <linux@treblig.org> Reported-by: Vjaceslavs Klimovs <vklimovs@gmail.com> Signed-off-by: Keith Busch <kbusch@kernel.org> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-27dm: fix race when loading and unloading a tableMikulas Patocka1-4/+8
If the userspace calls two concurrent table load ioctls and one of them succeeds and the other fails, there is a race condition because dm_setup_md_queue walks &md->table_devices without any lock. If the walk races with dm_table_destroy -> free_devices -> dm_put_table_device, there is access to invalid memory. Fix this race by extending the lock over the list walk. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org
2026-07-27dm: fix resume-vs-remove raceMikulas Patocka1-1/+1
If the user issues the resume ioctl and the remove ioctl at the same time, it may be possible that the device is resumed after it is suspended in __dm_destroy. The result is that the table is destroyed without calling the postsuspend method. Dm targets expect that they may be removed only after the postsuspend method method was called. If we break this expectation, it can cause misbehavior in various targets. For example - in the dm-integrity target, the reboot notifier is not unregistered, leading to use-after-free. Fix this bug by refusing to resume if the device is being destroyed. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Cc: stable@vger.kernel.org
2026-07-20blk-crypto: Allow control over whether hardware is usedEric Biggers1-1/+2
fscrypt uses inline encryption hardware only when the "inlinecrypt" mount option is given. I'd like to keep that behavior even after standardizing on the blk-crypto API for file contents encryption. That is, the default should continue to be the well-tested CPU-based encryption code, and the use of inline encryption hardware should continue to be an opt-in feature for systems where it's beneficial and has been fully validated (including verifying ciphertext correctness). To support this use case, extend blk_crypto_config with a new flag BLK_CRYPTO_CFG_ALLOW_HW. For now it's always set. Later commits will change that. Reviewed-by: Christoph Hellwig <hch@lst.de> Link: https://patch.msgid.link/20260713023708.9245-4-ebiggers@kernel.org Signed-off-by: Eric Biggers <ebiggers@kernel.org>
2026-07-20dm-pcache: remove unused 'allocated' variable in cache_data_alloc()Jianyun Gao1-5/+2
The 'allocated' variable is never non-zero when its value is consumed. 'to_alloc' was always equal to key->len, so replace them with key->len directly. Signed-off-by: Jianyun Gao <jianyungao89@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-20dm-pcache: replace tabs with spaces in comments to fix ASCII diagram alignmentJianyun Gao3-9/+9
Some editors interpret tabs as 4 spaces while others use 2, causing ASCII art diagrams in comments to misalign and hurt readability. Replace tabs with spaces to ensure consistent display across all editors. Signed-off-by: Jianyun Gao <jianyungao89@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-20dm-pcache: fix use-after-free and invalid seg operations in kset_replay()Jianyun Gao1-7/+6
In kset_replay, when key->seg_gen is stale (key->seg_gen < key->cache_pos.cache_seg->gen), cache_key_put(key) is called but then key->cache_pos.cache_seg is accessed as the argument to cache_seg_get(). This is a use-after-free on the freed key memory. Although mempool recycled memory is not immediately reclaimed or overwritten in practice, this is still a potential UAF bug. Additionally, for expired invalid keys, setting the cache->seg_map bit and calling cache_seg_get() is unreasonable since the corresponding segment data is no longer valid. Fix both issues by moving cache_seg_get() and __set_bit() after the gen check, so they only execute for valid keys, and using continue to skip invalid keys. Cc: stable@vger.kernel.org Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Signed-off-by: Jianyun Gao <jianyungao89@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-20dm-pcache: fix implicit u8 truncation of gc_percent in message handlerJianyun Gao1-2/+2
When setting gc_percent via message, kstrtoul parses the input into an unsigned long, which is then implicitly truncated to u8 when passed to pcache_cache_set_gc_percent(). For example, value 266 (0x10A) silently truncates to 10 (0x0A), successfully bypassing the > 90 upper bound check in pcache_cache_set_gc_percent(), and setting a different value than the user intended. Use kstrtou8 directly instead of kstrtoul, so that overflow values are properly rejected. Cc: stable@vger.kernel.org Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Signed-off-by: Jianyun Gao <jianyungao89@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-20dm raid1: reserve space for NUL-terminator in build_constructor_string()Ilya Krutskih1-0/+1
Reserve space for the termination NUL after the maximum 20 decimal digits of a long long value to avoid buffer overflow in sprintf(). Fixes: f5db4af466e2 ("dm raid1: add userspace log") Cc: stable@vger.kernel.org Signed-off-by: Ilya Krutskih <devsec@tpz.ru> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm vdo: don't read repair field in loop conditionMatthew Sakai1-3/+3
Respell the vio launch loop to use the existing vio_count value. The repair completion is not guaranteed to persist after all of the metadata_vios are launched. This can not currently cause problems due to the way vio callbacks are handled, but it is technically not safe to access those fields. Signed-off-by: Matthew Sakai <msakai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: only hand out initialized cache segmentsBryam Vargas1-2/+10
get_cache_segment() scans the segment map up to cache->n_segs, the physical device segment count, but cache_segs_init() only initializes the first cache_info->n_segs segments. A crafted image with cache_info->n_segs smaller than the device count leaves the remaining pcache_cache_segment structs zeroed (segment.data == NULL), and the allocator can hand one to cache_kset_close(), which writes through the returned segment's data pointer with no NULL check. Bound the allocator's search to cache_info->n_segs so only initialized segments are ever returned. A conforming cache sets n_segs equal to the device segment count, so this rejects nothing legitimate. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: validate the persisted dirty_tail chain at loadBryam Vargas3-0/+78
The writeback worker follows the persisted dirty_tail chain, which is decoded from the cache device independently of the key_tail chain that cache_replay() walks and bounds. A crafted image, whose on-media fields are authenticated only by a crc32c with a fixed seed, can aim dirty_tail at a chain of last ksets that never terminates, so cache_writeback_fn() re-arms itself with no delay forever. Walk the dirty_tail chain once at load with the same hop cap cache_replay() uses and fail the table load with -EIO if it does not reach an end within n_segs hops. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: validate on-media seg_num against the cache device sizeBryam Vargas1-1/+21
seg_num is read from the crc32c-only superblock, so whoever supplies the cache device on a table load (CAP_SYS_ADMIN) controls it. It sizes cache->segments[] and is the value every later on-media segment id is bounded against, yet it is never checked against the device. Because cache_dev->mapping is the direct map of the pmem, CACHE_DEV_SEGMENT() for a segment id past the device resolves to ordinary kernel memory beyond the mapping; a new-cache init reaching such an id has cache_seg_init() -> cache_dev_zero_range() memset() 12 KiB over that memory -- an out-of-bounds write into the kernel heap at table load. A zero seg_num makes the segment allocations ZERO_SIZE_PTR. Reject a seg_num that is zero, larger than the device can hold, or larger than PCACHE_CACHE_SEGS_MAX before it is used. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: clamp the tail kset read to the segment data regionBryam Vargas3-3/+3
The tail-kset read in cache_replay(), the writeback worker and the GC worker bounds its length by PCACHE_SEG_SIZE - seg_off, the raw segment size rather than the data region. A tail near the segment end reads past the segment data into the following control area. Clamp the read to cache_seg_remain(), the data region. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: bound the logical key offset from persistent memoryBryam Vargas1-0/+9
cache_key_decode() takes a key's logical off from the cache device and later indexes req_key_tree->subtrees[] by it in get_subtree(). An off past the device forms a subtree pointer outside the array, which rb_insert() writes through during replay. Reject a key of zero length, or whose off+len (computed in 64 bits) exceeds the device size, before it is used. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: detect a cycle in the last-kset chain during replayBryam Vargas1-1/+6
cache_replay() follows the on-media last-kset chain by next_cache_seg_id with no cond_resched(). A forged chain that points back into a segment it has already visited makes the replay loop follow it forever. Cap the last-kset hops at cache->n_segs; a valid chain visits each segment at most once. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: reject a kset that overruns its segmentBryam Vargas3-0/+15
cache_replay(), the writeback worker and the GC worker read a kset of get_kset_onmedia_size() bytes and advance the position by it. A forged key_num makes that size exceed the segment's remaining space, so the advance walks past the segment and trips the cache_pos_advance() BUG_ON. Reject a kset whose on-media size exceeds cache_seg_remain() before use. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: bound the persisted tail-position offsetBryam Vargas1-0/+4
cache_pos_decode() takes the persisted key_tail and dirty_tail seg_off from the cache device and addresses within the segment with it. A seg_off at or past the segment data_size, controllable by whoever supplies the device (CAP_SYS_ADMIN), reads past the segment data. Reject a decoded seg_off that is not below the segment data_size. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: validate kset key_num and intra-segment boundsBryam Vargas4-9/+38
Two more fields decoded from the cache device go unbounded. The kset key_num drives cache_kset_crc() and the replay loop in cache_replay(), the writeback worker and the GC worker, but only the magic and a fixed-seed CRC are checked first, so a non-last kset whose key_num exceeds the PCACHE_KSET_KEYS_MAX buffer reads past its end before the CRC compare. A key's intra-segment offset and length in cache_key_decode() are taken verbatim, so a key running past its segment is replayed into the cache tree and the data CRC check and every later read hit then copy adjacent persistent memory into the caller's bio -- an out-of-bounds read that leaks to user space. Both fields are controlled by whoever supplies the cache device (CAP_SYS_ADMIN); the CRC seed is public. Add kset_onmedia_valid() to bound key_num before any kset read, and reject a key whose offset plus length, computed in 64 bits, exceeds the segment data_size. Valid metadata is unaffected. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: validate geometry fields from on-disk cache_infoBryam Vargas1-0/+14
cache_segs_init() iterates cache_info->n_segs times indexing cache->segments[], which is sized to the cache device geometry, and get_seg_id() takes each segment id from the on-media cache_info and the per-segment next_seg link. Both come from cache device metadata that is only CRC-protected with a fixed public seed, so whoever supplies the cache device on a table load (CAP_SYS_ADMIN) controls them: an oversized n_segs or an out-of-range id drives an out-of-bounds access of cache->segments[] and a wild CACHE_DEV_SEGMENT() pointer into the device mapping -- an out-of-bounds read and write from on-disk data. Reject an n_segs that exceeds the device segment count and a segment id that is out of range before either is used. Valid metadata is unaffected. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-17dm-pcache: validate seg_id fields from persistent memoryBryam Vargas5-6/+63
cache_pos_decode(), cache_key_decode() and the last-kset branches of cache_replay(), the writeback worker and the GC worker take a cache segment id from the cache device metadata and index cache->segments[] with it without checking it against cache->n_segs. That metadata is only CRC-protected with a fixed public seed, so whoever supplies the cache device on a table load (CAP_SYS_ADMIN) controls the id; an out-of-range value forms a wild pcache_cache_segment pointer that is dereferenced and written through -- an out-of-bounds read and write driven by on-disk data. Add cache_seg_id_valid() and reject an out-of-range id at each decode site, failing the operation with -EIO instead of indexing past the array. Bound the id against the initialized-segment count (cache_info.n_segs) rather than the physical device total. A forged cache_info.n_segs below seg_num otherwise leaves segments[cache_info.n_segs..seg_num) as zeroed structs whose data pointer is NULL, so a forged id in that window would still be dereferenced. A later patch guarantees cache_info.n_segs <= seg_num, and a driver-created cache sets the two equal, so valid images are unaffected. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
2026-07-16dm-inlinecrypt: don't overwrite the error with -EINVALMikulas Patocka1-1/+0
get_key_size already returns -EINVAL on error, so we don't have to overwrite it again. No functional change. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>