From: Greg Kroah-Hartman Date: Tue, 27 Feb 2024 09:18:23 +0000 (+0100) Subject: 6.1-stable patches X-Git-Tag: v4.19.308~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2196dde712ce2edeb624de4bade5d75f622df677;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: erofs-fix-inconsistent-per-file-compression-format.patch erofs-simplify-compression-configuration-parser.patch --- diff --git a/queue-6.1/erofs-fix-inconsistent-per-file-compression-format.patch b/queue-6.1/erofs-fix-inconsistent-per-file-compression-format.patch new file mode 100644 index 00000000000..e412d227360 --- /dev/null +++ b/queue-6.1/erofs-fix-inconsistent-per-file-compression-format.patch @@ -0,0 +1,89 @@ +From 118a8cf504d7dfa519562d000f423ee3ca75d2c4 Mon Sep 17 00:00:00 2001 +From: Gao Xiang +Date: Sat, 13 Jan 2024 23:06:02 +0800 +Subject: erofs: fix inconsistent per-file compression format + +From: Gao Xiang + +commit 118a8cf504d7dfa519562d000f423ee3ca75d2c4 upstream. + +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: +Fixes: 8f89926290c4 ("erofs: get compression algorithms directly on mapping") +Fixes: 622ceaddb764 ("erofs: lzma compression support") +Reviewed-by: Yue Hu +Link: https://lore.kernel.org/r/20240113150602.1471050-1-hsiangkao@linux.alibaba.com +Signed-off-by: Gao Xiang +Signed-off-by: Gao Xiang +Signed-off-by: Yue Hu +Signed-off-by: Greg Kroah-Hartman +--- + fs/erofs/decompressor.c | 2 +- + fs/erofs/zmap.c | 23 +++++++++++++---------- + 2 files changed, 14 insertions(+), 11 deletions(-) + +--- a/fs/erofs/decompressor.c ++++ b/fs/erofs/decompressor.c +@@ -396,7 +396,7 @@ int z_erofs_parse_cfgs(struct super_bloc + 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); + } + +--- a/fs/erofs/zmap.c ++++ b/fs/erofs/zmap.c +@@ -610,7 +610,7 @@ static int z_erofs_do_map_blocks(struct + .map = map, + }; + int err = 0; +- unsigned int lclusterbits, endoff; ++ unsigned int lclusterbits, endoff, afmt; + unsigned long initial_lcn; + unsigned long long ofs, end; + +@@ -700,17 +700,20 @@ static int z_erofs_do_map_blocks(struct + err = -EFSCORRUPTED; + goto unmap_out; + } +- if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER) +- map->m_algorithmformat = +- Z_EROFS_COMPRESSION_INTERLACED; +- else +- map->m_algorithmformat = +- Z_EROFS_COMPRESSION_SHIFTED; +- } else if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2) { +- map->m_algorithmformat = vi->z_algorithmtype[1]; ++ afmt = vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER ? ++ Z_EROFS_COMPRESSION_INTERLACED : ++ Z_EROFS_COMPRESSION_SHIFTED; + } else { +- map->m_algorithmformat = vi->z_algorithmtype[0]; ++ afmt = m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2 ? ++ vi->z_algorithmtype[1] : vi->z_algorithmtype[0]; ++ if (!(EROFS_I_SB(inode)->available_compr_algs & (1 << afmt))) { ++ erofs_err(inode->i_sb, "inconsistent algorithmtype %u for nid %llu", ++ afmt, vi->nid); ++ err = -EFSCORRUPTED; ++ goto unmap_out; ++ } + } ++ map->m_algorithmformat = afmt; + + if ((flags & EROFS_GET_BLOCKS_FIEMAP) || + ((flags & EROFS_GET_BLOCKS_READMORE) && diff --git a/queue-6.1/erofs-simplify-compression-configuration-parser.patch b/queue-6.1/erofs-simplify-compression-configuration-parser.patch new file mode 100644 index 00000000000..4b24f5a8d8e --- /dev/null +++ b/queue-6.1/erofs-simplify-compression-configuration-parser.patch @@ -0,0 +1,307 @@ +From efb4fb02cef3ab410b603c8f0e1c67f61d55f542 Mon Sep 17 00:00:00 2001 +From: Gao Xiang +Date: Sun, 22 Oct 2023 21:09:57 +0800 +Subject: erofs: simplify compression configuration parser + +From: Gao Xiang + +commit efb4fb02cef3ab410b603c8f0e1c67f61d55f542 upstream. + +Move erofs_load_compr_cfgs() into decompressor.c as well as introduce +a callback instead of a hard-coded switch for each algorithm for +simplicity. + +Reviewed-by: Chao Yu +Signed-off-by: Gao Xiang +Link: https://lore.kernel.org/r/20231022130957.11398-1-xiang@kernel.org +Stable-dep-of: 118a8cf504d7 ("erofs: fix inconsistent per-file compression format") +Signed-off-by: Yue Hu +Signed-off-by: Greg Kroah-Hartman +--- + fs/erofs/compress.h | 4 ++ + fs/erofs/decompressor.c | 60 ++++++++++++++++++++++++++++++++++- + fs/erofs/decompressor_lzma.c | 4 +- + fs/erofs/internal.h | 28 +--------------- + fs/erofs/super.c | 72 +++++-------------------------------------- + 5 files changed, 76 insertions(+), 92 deletions(-) + +--- a/fs/erofs/compress.h ++++ b/fs/erofs/compress.h +@@ -21,6 +21,8 @@ struct z_erofs_decompress_req { + }; + + struct z_erofs_decompressor { ++ int (*config)(struct super_block *sb, struct erofs_super_block *dsb, ++ void *data, int size); + int (*decompress)(struct z_erofs_decompress_req *rq, + struct page **pagepool); + char *name; +@@ -93,6 +95,8 @@ int z_erofs_decompress(struct z_erofs_de + struct page **pagepool); + + /* prototypes for specific algorithms */ ++int z_erofs_load_lzma_config(struct super_block *sb, ++ struct erofs_super_block *dsb, void *data, int size); + int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq, + struct page **pagepool); + #endif +--- a/fs/erofs/decompressor.c ++++ b/fs/erofs/decompressor.c +@@ -24,11 +24,11 @@ struct z_erofs_lz4_decompress_ctx { + unsigned int oend; + }; + +-int z_erofs_load_lz4_config(struct super_block *sb, +- struct erofs_super_block *dsb, +- struct z_erofs_lz4_cfgs *lz4, int size) ++static int z_erofs_load_lz4_config(struct super_block *sb, ++ struct erofs_super_block *dsb, void *data, int size) + { + struct erofs_sb_info *sbi = EROFS_SB(sb); ++ struct z_erofs_lz4_cfgs *lz4 = data; + u16 distance; + + if (lz4) { +@@ -374,17 +374,71 @@ static struct z_erofs_decompressor decom + .name = "interlaced" + }, + [Z_EROFS_COMPRESSION_LZ4] = { ++ .config = z_erofs_load_lz4_config, + .decompress = z_erofs_lz4_decompress, + .name = "lz4" + }, + #ifdef CONFIG_EROFS_FS_ZIP_LZMA + [Z_EROFS_COMPRESSION_LZMA] = { ++ .config = z_erofs_load_lzma_config, + .decompress = z_erofs_lzma_decompress, + .name = "lzma" + }, + #endif + }; + ++int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb) ++{ ++ struct erofs_sb_info *sbi = EROFS_SB(sb); ++ struct erofs_buf buf = __EROFS_BUF_INITIALIZER; ++ unsigned int algs, alg; ++ erofs_off_t offset; ++ int size, ret = 0; ++ ++ if (!erofs_sb_has_compr_cfgs(sbi)) { ++ sbi->available_compr_algs = Z_EROFS_COMPRESSION_LZ4; ++ return z_erofs_load_lz4_config(sb, dsb, NULL, 0); ++ } ++ ++ sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs); ++ if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) { ++ erofs_err(sb, "unidentified algorithms %x, please upgrade kernel", ++ sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS); ++ return -EOPNOTSUPP; ++ } ++ ++ offset = EROFS_SUPER_OFFSET + sbi->sb_size; ++ alg = 0; ++ for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) { ++ void *data; ++ ++ if (!(algs & 1)) ++ continue; ++ ++ data = erofs_read_metadata(sb, &buf, &offset, &size); ++ if (IS_ERR(data)) { ++ ret = PTR_ERR(data); ++ break; ++ } ++ ++ if (alg >= ARRAY_SIZE(decompressors) || ++ !decompressors[alg].config) { ++ erofs_err(sb, "algorithm %d isn't enabled on this kernel", ++ alg); ++ ret = -EOPNOTSUPP; ++ } else { ++ ret = decompressors[alg].config(sb, ++ dsb, data, size); ++ } ++ ++ kfree(data); ++ if (ret) ++ break; ++ } ++ erofs_put_metabuf(&buf); ++ return ret; ++} ++ + int z_erofs_decompress(struct z_erofs_decompress_req *rq, + struct page **pagepool) + { +--- a/fs/erofs/decompressor_lzma.c ++++ b/fs/erofs/decompressor_lzma.c +@@ -72,10 +72,10 @@ int z_erofs_lzma_init(void) + } + + int z_erofs_load_lzma_config(struct super_block *sb, +- struct erofs_super_block *dsb, +- struct z_erofs_lzma_cfgs *lzma, int size) ++ struct erofs_super_block *dsb, void *data, int size) + { + static DEFINE_MUTEX(lzma_resize_mutex); ++ struct z_erofs_lzma_cfgs *lzma = data; + unsigned int dict_size, i; + struct z_erofs_lzma *strm, *head = NULL; + int err; +--- a/fs/erofs/internal.h ++++ b/fs/erofs/internal.h +@@ -471,6 +471,8 @@ struct erofs_map_dev { + + /* data.c */ + extern const struct file_operations erofs_file_fops; ++void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, ++ erofs_off_t *offset, int *lengthp); + void erofs_unmap_metabuf(struct erofs_buf *buf); + void erofs_put_metabuf(struct erofs_buf *buf); + void *erofs_bread(struct erofs_buf *buf, struct inode *inode, +@@ -565,9 +567,7 @@ void z_erofs_exit_zip_subsystem(void); + int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, + struct erofs_workgroup *egrp); + int erofs_try_to_free_cached_page(struct page *page); +-int z_erofs_load_lz4_config(struct super_block *sb, +- struct erofs_super_block *dsb, +- struct z_erofs_lz4_cfgs *lz4, int len); ++int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb); + #else + static inline void erofs_shrinker_register(struct super_block *sb) {} + static inline void erofs_shrinker_unregister(struct super_block *sb) {} +@@ -575,36 +575,14 @@ static inline int erofs_init_shrinker(vo + static inline void erofs_exit_shrinker(void) {} + static inline int z_erofs_init_zip_subsystem(void) { return 0; } + static inline void z_erofs_exit_zip_subsystem(void) {} +-static inline int z_erofs_load_lz4_config(struct super_block *sb, +- struct erofs_super_block *dsb, +- struct z_erofs_lz4_cfgs *lz4, int len) +-{ +- if (lz4 || dsb->u1.lz4_max_distance) { +- erofs_err(sb, "lz4 algorithm isn't enabled"); +- return -EINVAL; +- } +- return 0; +-} + #endif /* !CONFIG_EROFS_FS_ZIP */ + + #ifdef CONFIG_EROFS_FS_ZIP_LZMA + int z_erofs_lzma_init(void); + void z_erofs_lzma_exit(void); +-int z_erofs_load_lzma_config(struct super_block *sb, +- struct erofs_super_block *dsb, +- struct z_erofs_lzma_cfgs *lzma, int size); + #else + static inline int z_erofs_lzma_init(void) { return 0; } + static inline int z_erofs_lzma_exit(void) { return 0; } +-static inline int z_erofs_load_lzma_config(struct super_block *sb, +- struct erofs_super_block *dsb, +- struct z_erofs_lzma_cfgs *lzma, int size) { +- if (lzma) { +- erofs_err(sb, "lzma algorithm isn't enabled"); +- return -EINVAL; +- } +- return 0; +-} + #endif /* !CONFIG_EROFS_FS_ZIP */ + + /* flags for erofs_fscache_register_cookie() */ +--- a/fs/erofs/super.c ++++ b/fs/erofs/super.c +@@ -126,8 +126,8 @@ static bool check_layout_compatibility(s + + #ifdef CONFIG_EROFS_FS_ZIP + /* read variable-sized metadata, offset will be aligned by 4-byte */ +-static void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, +- erofs_off_t *offset, int *lengthp) ++void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, ++ erofs_off_t *offset, int *lengthp) + { + u8 *buffer, *ptr; + int len, i, cnt; +@@ -159,64 +159,15 @@ static void *erofs_read_metadata(struct + } + return buffer; + } +- +-static int erofs_load_compr_cfgs(struct super_block *sb, +- struct erofs_super_block *dsb) +-{ +- struct erofs_sb_info *sbi = EROFS_SB(sb); +- struct erofs_buf buf = __EROFS_BUF_INITIALIZER; +- unsigned int algs, alg; +- erofs_off_t offset; +- int size, ret = 0; +- +- sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs); +- if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) { +- erofs_err(sb, "try to load compressed fs with unsupported algorithms %x", +- sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS); +- return -EINVAL; +- } +- +- offset = EROFS_SUPER_OFFSET + sbi->sb_size; +- alg = 0; +- for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) { +- void *data; +- +- if (!(algs & 1)) +- continue; +- +- data = erofs_read_metadata(sb, &buf, &offset, &size); +- if (IS_ERR(data)) { +- ret = PTR_ERR(data); +- break; +- } +- +- switch (alg) { +- case Z_EROFS_COMPRESSION_LZ4: +- ret = z_erofs_load_lz4_config(sb, dsb, data, size); +- break; +- case Z_EROFS_COMPRESSION_LZMA: +- ret = z_erofs_load_lzma_config(sb, dsb, data, size); +- break; +- default: +- DBG_BUGON(1); +- ret = -EFAULT; +- } +- kfree(data); +- if (ret) +- break; +- } +- erofs_put_metabuf(&buf); +- return ret; +-} + #else +-static int erofs_load_compr_cfgs(struct super_block *sb, +- struct erofs_super_block *dsb) ++static int z_erofs_parse_cfgs(struct super_block *sb, ++ struct erofs_super_block *dsb) + { +- if (dsb->u1.available_compr_algs) { +- erofs_err(sb, "try to load compressed fs when compression is disabled"); +- return -EINVAL; +- } +- return 0; ++ if (!dsb->u1.available_compr_algs) ++ return 0; ++ ++ erofs_err(sb, "compression disabled, unable to mount compressed EROFS"); ++ return -EOPNOTSUPP; + } + #endif + +@@ -398,10 +349,7 @@ static int erofs_read_superblock(struct + } + + /* parse on-disk compression configurations */ +- if (erofs_sb_has_compr_cfgs(sbi)) +- ret = erofs_load_compr_cfgs(sb, dsb); +- else +- ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0); ++ ret = z_erofs_parse_cfgs(sb, dsb); + if (ret < 0) + goto out; + diff --git a/queue-6.1/series b/queue-6.1/series index aca620dbf6b..775ddaf3903 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -183,3 +183,5 @@ net-phy-realtek-fix-rtl8211f_config_init-for-rtl8211.patch drm-syncobj-call-drm_syncobj_fence_add_wait-when-wai.patch drm-amd-display-fix-memory-leak-in-dm_sw_fini.patch i2c-imx-when-being-a-target-mark-the-last-read-as-pr.patch +erofs-simplify-compression-configuration-parser.patch +erofs-fix-inconsistent-per-file-compression-format.patch