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 algorithm for specific inodes; thus, an unexpected "BUG: kernel NULL pointer dereference" can be raised. Fix this by checking against `sbi->available_compr_algs` for each compressed inode. Incorrect !erofs_sb_has_compr_cfgs preset bitmap is now fixed together since it was harmless previously. Reported-by: <[email protected]> Fixes: 14373711dd54 ("erofs: add on-disk compression configurations") Signed-off-by: Gao Xiang <[email protected]> --- change since v1: - fix left-shift overflow (undefined behavior). fs/erofs/decompressor.c | 2 +- fs/erofs/zmap.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c index 021be5feb1bc..af98e88908ee 100644 --- a/fs/erofs/decompressor.c +++ b/fs/erofs/decompressor.c @@ -398,7 +398,7 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb) int size, ret = 0; if (!erofs_sb_has_compr_cfgs(sbi)) { - sbi->available_compr_algs = Z_EROFS_COMPRESSION_LZ4; + sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4; return z_erofs_load_lz4_config(sb, dsb, NULL, 0); } diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c index 7b55111fd533..6f10bc8bbb1c 100644 --- a/fs/erofs/zmap.c +++ b/fs/erofs/zmap.c @@ -578,6 +578,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) { struct erofs_inode *const vi = EROFS_I(inode); struct super_block *const sb = inode->i_sb; + struct erofs_sb_info *sbi = EROFS_SB(sb); int err, headnr; erofs_off_t pos; struct erofs_buf buf = __EROFS_BUF_INITIALIZER; @@ -624,10 +625,12 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) headnr = 0; if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX || - vi->z_algorithmtype[++headnr] >= Z_EROFS_COMPRESSION_MAX) { - erofs_err(sb, "unknown HEAD%u format %u for nid %llu, please upgrade kernel", + !(sbi->available_compr_algs & (1 << vi->z_algorithmtype[0])) || + vi->z_algorithmtype[++headnr] >= Z_EROFS_COMPRESSION_MAX || + !(sbi->available_compr_algs & (1 << vi->z_algorithmtype[headnr]))) { + erofs_err(sb, "inconsistent HEAD%u algorithm format %u for nid %llu", headnr + 1, vi->z_algorithmtype[headnr], vi->nid); - err = -EOPNOTSUPP; + err = -EFSCORRUPTED; goto out_put_metabuf; } -- 2.39.3
