]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Feb 2024 09:18:23 +0000 (10:18 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Feb 2024 09:18:23 +0000 (10:18 +0100)
added patches:
erofs-fix-inconsistent-per-file-compression-format.patch
erofs-simplify-compression-configuration-parser.patch

queue-6.1/erofs-fix-inconsistent-per-file-compression-format.patch [new file with mode: 0644]
queue-6.1/erofs-simplify-compression-configuration-parser.patch [new file with mode: 0644]
queue-6.1/series

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 (file)
index 0000000..e412d22
--- /dev/null
@@ -0,0 +1,89 @@
+From 118a8cf504d7dfa519562d000f423ee3ca75d2c4 Mon Sep 17 00:00:00 2001
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+Date: Sat, 13 Jan 2024 23:06:02 +0800
+Subject: erofs: fix inconsistent per-file compression format
+
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+
+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: <bugreport@ubisectech.com>
+Fixes: 8f89926290c4 ("erofs: get compression algorithms directly on mapping")
+Fixes: 622ceaddb764 ("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>
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+Signed-off-by: Yue Hu <huyue2@coolpad.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..4b24f5a
--- /dev/null
@@ -0,0 +1,307 @@
+From efb4fb02cef3ab410b603c8f0e1c67f61d55f542 Mon Sep 17 00:00:00 2001
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+Date: Sun, 22 Oct 2023 21:09:57 +0800
+Subject: erofs: simplify compression configuration parser
+
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+
+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 <chao@kernel.org>
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+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 <huyue2@coolpad.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
index aca620dbf6bda9a560ba92bc96b41d16832f23f3..775ddaf3903ccf6907e239ff295f74e2ce4b7f28 100644 (file)
@@ -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