]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
erofs: fix interlaced plain identification for encoded extents
authorGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 24 Feb 2026 10:31:25 +0000 (18:31 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 25 Feb 2026 09:40:58 +0000 (17:40 +0800)
Only plain data whose start position and on-disk physical length are
both aligned to the block size should be classified as interlaced
plain extents. Otherwise, it must be treated as shifted plain extents.

This issue was found by syzbot using a crafted compressed image
containing plain extents with unaligned physical lengths, which can
cause OOB read in z_erofs_transform_plain().

Reported-and-tested-by: syzbot+d988dc155e740d76a331@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/r/699d5714.050a0220.cdd3c.03e7.GAE@google.com
Fixes: 1d191b4ca51d ("erofs: implement encoded extent metadata")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
fs/erofs/zmap.c

index c8d8e129eb4bad1feca19324449f86952b5b7208..30775502b56da2b0b468ce1fc29c9c18e7c7ac63 100644 (file)
@@ -513,6 +513,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
        unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
        erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) +
                                   vi->inode_isize + vi->xattr_isize), recsz);
+       unsigned int bmask = sb->s_blocksize - 1;
        bool in_mbox = erofs_inode_in_metabox(inode);
        erofs_off_t lend = inode->i_size;
        erofs_off_t l, r, mid, pa, la, lstart;
@@ -596,17 +597,17 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
                        map->m_flags |= EROFS_MAP_MAPPED |
                                EROFS_MAP_FULL_MAPPED | EROFS_MAP_ENCODED;
                        fmt = map->m_plen >> Z_EROFS_EXTENT_PLEN_FMT_BIT;
+                       if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
+                               map->m_flags |= EROFS_MAP_PARTIAL_REF;
+                       map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
                        if (fmt)
                                map->m_algorithmformat = fmt - 1;
-                       else if (interlaced && !erofs_blkoff(sb, map->m_pa))
+                       else if (interlaced && !((map->m_pa | map->m_plen) & bmask))
                                map->m_algorithmformat =
                                        Z_EROFS_COMPRESSION_INTERLACED;
                        else
                                map->m_algorithmformat =
                                        Z_EROFS_COMPRESSION_SHIFTED;
-                       if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
-                               map->m_flags |= EROFS_MAP_PARTIAL_REF;
-                       map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
                }
        }
        map->m_llen = lend - map->m_la;