Skip to content

Commit 118a8cf

Browse files
committed
erofs: fix inconsistent per-file compression format
EROFS can select compression algorithms on a per-file basis, and each per-file compression algorithm needs to be marked in the on-disk superblock for initialization. However, syzkaller can generate inconsistent crafted images that use an unsupported algorithmtype for specific inodes, e.g. use MicroLZMA algorithmtype even it's not set in `sbi->available_compr_algs`. This can lead to an unexpected "BUG: kernel NULL pointer dereference" if the corresponding decompressor isn't built-in. Fix this by checking against `sbi->available_compr_algs` for each m_algorithmformat request. Incorrect !erofs_sb_has_compr_cfgs preset bitmap is now fixed together since it was harmless previously. Reported-by: <bugreport@ubisectech.com> Fixes: 8f89926 ("erofs: get compression algorithms directly on mapping") Fixes: 622cead ("erofs: lzma compression support") Reviewed-by: Yue Hu <huyue2@coolpad.com> Link: https://lore.kernel.org/r/20240113150602.1471050-1-hsiangkao@linux.alibaba.com Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
1 parent 0dd3ee3 commit 118a8cf

File tree

2 files changed

+14
-11
lines changed

2 files changed

+14
-11
lines changed

fs/erofs/decompressor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
398398
int size, ret = 0;
399399

400400
if (!erofs_sb_has_compr_cfgs(sbi)) {
401-
sbi->available_compr_algs = Z_EROFS_COMPRESSION_LZ4;
401+
sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
402402
return z_erofs_load_lz4_config(sb, dsb, NULL, 0);
403403
}
404404

fs/erofs/zmap.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ static int z_erofs_do_map_blocks(struct inode *inode,
458458
.map = map,
459459
};
460460
int err = 0;
461-
unsigned int lclusterbits, endoff;
461+
unsigned int lclusterbits, endoff, afmt;
462462
unsigned long initial_lcn;
463463
unsigned long long ofs, end;
464464

@@ -547,17 +547,20 @@ static int z_erofs_do_map_blocks(struct inode *inode,
547547
err = -EFSCORRUPTED;
548548
goto unmap_out;
549549
}
550-
if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER)
551-
map->m_algorithmformat =
552-
Z_EROFS_COMPRESSION_INTERLACED;
553-
else
554-
map->m_algorithmformat =
555-
Z_EROFS_COMPRESSION_SHIFTED;
556-
} else if (m.headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2) {
557-
map->m_algorithmformat = vi->z_algorithmtype[1];
550+
afmt = vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER ?
551+
Z_EROFS_COMPRESSION_INTERLACED :
552+
Z_EROFS_COMPRESSION_SHIFTED;
558553
} else {
559-
map->m_algorithmformat = vi->z_algorithmtype[0];
554+
afmt = m.headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2 ?
555+
vi->z_algorithmtype[1] : vi->z_algorithmtype[0];
556+
if (!(EROFS_I_SB(inode)->available_compr_algs & (1 << afmt))) {
557+
erofs_err(inode->i_sb, "inconsistent algorithmtype %u for nid %llu",
558+
afmt, vi->nid);
559+
err = -EFSCORRUPTED;
560+
goto unmap_out;
561+
}
560562
}
563+
map->m_algorithmformat = afmt;
561564

562565
if ((flags & EROFS_GET_BLOCKS_FIEMAP) ||
563566
((flags & EROFS_GET_BLOCKS_READMORE) &&

0 commit comments

Comments
 (0)