[PATCH] erofs-utils: lib: fix null deref on incremental uncompressed builds

Jonathan Calmels <[email protected]>
Newsgroups org.ozlabs.lists.linux-erofs
Message-ID <[email protected]>
On incremental uncompressed builds, z_erofs_parse_cfgs takes the legacy path for
images without COMPR_CFGS and unconditionally sets available_compr_algs
to LZ4, regardless of whether compression was actually used.
When the current build requests no compression, z_erofs_compress_init
returns early leaving ccfg uninitialized and available_compr_algs
unchanged, subsquently causing a crash when alg is dereferenced.

Fix this by gating compression on whether the per-algorithm ccfg entry was
actually initialized rather than trusting the superblock bitmask.

Simple repro with alpine rootfs:

./mkfs.erofs /tmp/alpine.erofs /tmp/alpine
./mkfs.erofs --incremental=data /tmp/alpine.erofs /tmp/alpine

mkfs.erofs 1.9-g1d5bacbb
<W> erofs: EXPERIMENTAL incremental build in use. Use at your own risk!
Processing bin/sh ...zsh: segmentation fault (core dumped)  ./mkfs.erofs --incremental=data /tmp/alpine.erofs /tmp/alpine

Signed-off-by: Jonathan Calmels <[email protected]>
---
 lib/compress.c          | 10 ++++++++++
 lib/inode.c             | 17 ++++++++++++-----
 lib/liberofs_compress.h |  1 +
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index ea07409..e5bb784 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -2186,6 +2186,16 @@ static int z_erofs_build_compr_cfgs(struct erofs_importer *im,
 	return ret;
 }
 
+bool z_erofs_compress_alg_enabled(const struct erofs_importer *im, u8 algid)
+{
+	struct erofs_sb_info *sbi = im->sbi;
+
+	if (!sbi->available_compr_algs || !sbi->zmgr || algid >= EROFS_MAX_COMPR_CFGS)
+		return false;
+
+	return sbi->zmgr->ccfg[algid].enable;
+}
+
 int z_erofs_compress_init(struct erofs_importer *im)
 {
 	const struct erofs_importer_params *params = im->params;
diff --git a/lib/inode.c b/lib/inode.c
index c225faa..05344e7 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -624,9 +624,18 @@ int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf)
 static bool erofs_file_is_compressible(struct erofs_importer *im,
 				       struct erofs_inode *inode)
 {
-	if (erofs_is_metabox_inode(inode) &&
-	    !im->params->pclusterblks_metabox)
+	u8 algid;
+
+	if (erofs_is_metabox_inode(inode)) {
+		if (!im->params->pclusterblks_metabox)
+			return false;
+		algid = cfg.c_mkfs_metabox_algid;
+	} else {
+		algid = inode->z_algorithmtype[0];
+	}
+	if (!z_erofs_compress_alg_enabled(im, algid))
 		return false;
+
 	if (cfg.c_compress_hints_file)
 		return z_erofs_apply_compress_hints(im, inode);
 	return true;
@@ -2049,7 +2058,6 @@ static int erofs_mkfs_begin_nondirectory(const struct erofs_mkfs_btctx *btctx,
 			return ret;
 
 		if (inode->datasource != EROFS_INODE_DATA_SOURCE_REBUILD_BLOB &&
-		    inode->sbi->available_compr_algs &&
 		    erofs_file_is_compressible(im, inode)) {
 			ctx.ictx = erofs_prepare_compressed_file(im, inode);
 			if (IS_ERR(ctx.ictx))
@@ -2378,8 +2386,7 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_importer *im,
 		return ERR_PTR(ret);
 	}
 
-	if (sbi->available_compr_algs &&
-	    erofs_file_is_compressible(im, inode)) {
+	if (erofs_file_is_compressible(im, inode)) {
 		ictx = erofs_prepare_compressed_file(im, inode);
 		if (IS_ERR(ictx))
 			return ERR_CAST(ictx);
diff --git a/lib/liberofs_compress.h b/lib/liberofs_compress.h
index da6eb1a..32e8e03 100644
--- a/lib/liberofs_compress.h
+++ b/lib/liberofs_compress.h
@@ -14,6 +14,7 @@
 
 struct z_erofs_compress_ictx;
 
+bool z_erofs_compress_alg_enabled(const struct erofs_importer *im, u8 algid);
 void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
 void *erofs_prepare_compressed_file(struct erofs_importer *im,
 				    struct erofs_inode *inode);
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.