too_many_discard_blocks() uses sector_div(), whose divisor is a u32. discard_block_size is a 64-bit sector_t that calculate_discard_block_size() keeps doubling, so once it reaches a multiple of 2^32 the divisor is truncated to 0 and the division traps with a divide error. Smaller values above 2^32 are also silently truncated, giving a wrong quotient.
This needs an origin of more than 2^45 sectors, which is unrealistic (this is a thing still in 2026!!) for a real device but reachable with a fuzzer. Use div64_u64 so the full 64-bit divisor is used. Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=3e16980543e238b95bd1 Fixes: 08b184514f65d ("dm cache: revert "prevent corruption caused by discard_block_size > cache_block_size"") Cc: [email protected] Signed-off-by: Drif Abdelmalek Mohamed Said <[email protected]> --- drivers/md/dm-cache-target.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 1a5072425c4a..2d40d6047ef1 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -2383,9 +2383,7 @@ static int create_cache_policy(struct cache *cache, struct cache_args *ca, static bool too_many_discard_blocks(sector_t discard_block_size, sector_t origin_size) { - (void) sector_div(origin_size, discard_block_size); - - return origin_size > MAX_DISCARD_BLOCKS; + return div64_u64(origin_size, discard_block_size) > MAX_DISCARD_BLOCKS; } static sector_t calculate_discard_block_size(sector_t cache_block_size, -- 2.43.0
