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]> --- fs/erofs/decompressor.c | 2 +- fs/erofs/zmap.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 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..d513f2cd7521 100644 --- a/fs/erofs/zmap.c +++ b/fs/erofs/zmap.c @@ -578,7 +578,8 @@ 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; - int err, headnr; + struct erofs_sb_info *sbi = EROFS_SB(sb); + int err, nr; erofs_off_t pos; struct erofs_buf buf = __EROFS_BUF_INITIALIZER; void *kaddr; @@ -622,12 +623,12 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) vi->z_algorithmtype[0] = h->h_algorithmtype & 15; vi->z_algorithmtype[1] = h->h_algorithmtype >> 4; - 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", - headnr + 1, vi->z_algorithmtype[headnr], vi->nid); - err = -EOPNOTSUPP; + nr = 0; + if (!(sbi->available_compr_algs & (1 << vi->z_algorithmtype[0])) || + !(sbi->available_compr_algs & (1 << vi->z_algorithmtype[++nr]))) { + erofs_err(sb, "inconsistent HEAD%u algorithm format %u for nid %llu", + nr + 1, vi->z_algorithmtype[nr], vi->nid); + err = -EFSCORRUPTED; goto out_put_metabuf; } -- 2.39.3
