ext4fs: Fix: Read outside partition error (take 2)
authorTony Dinh <mibodhi@gmail.com>
Wed, 28 May 2025 19:48:39 +0000 (12:48 -0700)
committerTom Rini <trini@konsulko.com>
Thu, 12 Jun 2025 19:22:26 +0000 (13:22 -0600)
Use lbaint_t for blknr to avoid overflow in ext4fs_read_file().

Background:

blknr (block number) used in ext4fs_read_file() could be increased to a
very large value and causes a wrap around at 32 bit signed integer max,
thus becomes negative. This results in an out-of-normal range for sector
number (during the assignment delayed_start = blknr) where delayed_start
sector is typed uint64 lbaint_t. This causes the "Read outside partition"
error.

Looks like we also have this overflown problem in ext4_write.c that needs
to be addressed.

This patch was tested on the Synology DS116 (Armada 385) board, and a
4TB Seagate HDD.

Signed-off-by: Tony Dinh <mibodhi@gmail.com>
fs/ext4/ext4fs.c

index bd058a0..9be9959 100644 (file)
@@ -102,17 +102,21 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
        blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
 
        for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
-               long int blknr;
+               lbaint_t blknr;
+               long blknr_and_status;
                int blockoff = pos - (blocksize * i);
                int blockend = blocksize;
                int skipfirst = 0;
-               blknr = read_allocated_block(&node->inode, i, &cache);
-               if (blknr < 0) {
+               blknr_and_status = read_allocated_block(&node->inode, i, &cache);
+               if (blknr_and_status < 0) {
                        ext_cache_fini(&cache);
                        return -1;
                }
 
-               blknr = blknr << log2_fs_blocksize;
+               /* Block number could becomes very large when CONFIG_SYS_64BIT_LBA is enabled
+                * and wrap around at max long int
+                */
+               blknr = (lbaint_t)blknr_and_status << log2_fs_blocksize;
 
                /* Last block.  */
                if (i == blockcnt - 1) {