From: John Garry john.g.garry@oracle.com
[ Upstream commit 448dfecc7ff807822ecd47a5c052acedca7d09e8 ]
In blk_stack_limits(), we check that the t->chunk_sectors value is a multiple of the t->physical_block_size value.
However, by finding the chunk_sectors value in bytes, we may overflow the unsigned int which holds chunk_sectors, so change the check to be based on sectors.
Reviewed-by: Hannes Reinecke hare@suse.de Reviewed-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: John Garry john.g.garry@oracle.com Reviewed-by: Damien Le Moal dlemoal@kernel.org Link: https://lore.kernel.org/r/20250729091448.1691334-2-john.g.garry@oracle.com Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
**Backport Status: YES**
## Extensive Analysis
This commit should be backported to stable kernel trees for the following reasons:
### 1. **It fixes a real integer overflow bug** The original code performs `(t->chunk_sectors << 9)` which can cause an integer overflow. Since both `chunk_sectors` and `physical_block_size` are `unsigned int` (32-bit), when `chunk_sectors` is larger than 8,388,607 (2^23 - 1), shifting it left by 9 bits (multiplying by 512) will overflow the 32-bit unsigned integer. This overflow can lead to incorrect alignment checks.
### 2. **The fix is minimal and contained** The change is a single-line modification that replaces: ```c if ((t->chunk_sectors << 9) & (t->physical_block_size - 1)) ``` with: ```c if (t->chunk_sectors % (t->physical_block_size >> SECTOR_SHIFT)) ```
This mathematically equivalent check avoids the overflow by dividing `physical_block_size` by the sector size (512 bytes) instead of multiplying `chunk_sectors` by 512.
### 3. **It's a correctness issue in critical block layer code** The `blk_stack_limits()` function is fundamental to the block layer's device stacking functionality, used by MD, DM, and other stacked block devices. An overflow here could lead to: - Incorrect alignment detection - Improper chunk_sectors being cleared when it shouldn't be - Potential data corruption or I/O errors in stacked block devices
### 4. **The fix has low regression risk** - The new calculation is mathematically equivalent to the intended check - It only changes how the comparison is performed, not the logic - The fix has been reviewed by multiple maintainers (Hannes Reinecke, Martin K. Petersen, Damien Le Moal) - No new features or architectural changes are introduced
### 5. **Real-world impact potential** Modern storage devices can have large chunk sizes. For example: - NVMe devices with large zones could have chunk_sectors approaching or exceeding the overflow threshold - RAID configurations with large stripe sizes - This becomes more likely as storage devices grow in capacity and complexity
### 6. **Follows stable kernel criteria** According to stable kernel rules, this qualifies because it: - Fixes a bug that users can potentially hit - Is obviously correct and tested - Is small (single line change) - Fixes only one thing - Has no dependencies on other patches
The commit message clearly describes the problem (overflow in unsigned int) and the solution (changing the check to avoid overflow). The fix maintains the same semantic meaning while being overflow-safe, making it an ideal candidate for stable backporting.
block/blk-settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block/blk-settings.c b/block/blk-settings.c index a000daafbfb4..88890e904320 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -779,7 +779,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, }
/* chunk_sectors a multiple of the physical block size? */ - if ((t->chunk_sectors << 9) & (t->physical_block_size - 1)) { + if (t->chunk_sectors % (t->physical_block_size >> SECTOR_SHIFT)) { t->chunk_sectors = 0; t->flags |= BLK_FLAG_MISALIGNED; ret = -1;