* [PATCH] erofs-utils: lib: fix null deref on incremental uncompressed builds
@ 2026-06-11 23:54 Jonathan Calmels
2026-06-12 2:20 ` [PATCH] erofs-utils: lib: separate plain and compressed filesystems formally Gao Xiang
0 siblings, 1 reply; 3+ messages in thread
From: Jonathan Calmels @ 2026-06-11 23:54 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang, Jonathan Calmels
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 <jcalmels@nvidia.com>
---
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
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH] erofs-utils: lib: separate plain and compressed filesystems formally
2026-06-11 23:54 [PATCH] erofs-utils: lib: fix null deref on incremental uncompressed builds Jonathan Calmels
@ 2026-06-12 2:20 ` Gao Xiang
2026-06-12 8:06 ` Jonathan Calmels
0 siblings, 1 reply; 3+ messages in thread
From: Gao Xiang @ 2026-06-12 2:20 UTC (permalink / raw)
To: linux-erofs; +Cc: oliver.yang, Gao Xiang, Jonathan Calmels
Source kernel commit: 7cef3c8341940febf75db6c25199cd83fb74d52f
!lz4_0padding is simply an ancient layout which is mainly used for
Linux kernels < 5.3 (prior to the initial EROFS formal version) and
generated with the option `-Elegacy-compress` by mkfs.erofs between
1.0 and 1.8.x.
So recently Linux 7.0+ kernels simply use lz4_0padding as another
indicator of whether it's an (LZ4) compressed filesystem. Follow
the new behavior for erofs-utils too to fix an incremental data
build issue [1].
Reported-by: Jonathan Calmels <jcalmels@nvidia.com>
[1] https://lore.kernel.org/r/20260611235404.1620899-1-jcalmels@nvidia.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
---
Hi Jonathan,
Could you confirm if this issue works for you?
Thanks,
Gao Xiang
lib/decompress.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/lib/decompress.c b/lib/decompress.c
index d23135e0cd43..e6d14f4cbd94 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -466,17 +466,12 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
char *dest = rq->out;
char *src = rq->in;
char *buff = NULL;
- bool support_0padding = false;
unsigned int inputmargin = 0;
struct erofs_sb_info *sbi = rq->sbi;
- if (erofs_sb_has_lz4_0padding(sbi)) {
- support_0padding = true;
-
- inputmargin = z_erofs_fixup_insize((u8 *)src, rq->inputsize);
- if (inputmargin >= rq->inputsize)
- return -EFSCORRUPTED;
- }
+ inputmargin = z_erofs_fixup_insize((u8 *)src, rq->inputsize);
+ if (inputmargin >= rq->inputsize)
+ return -EFSCORRUPTED;
if (rq->decodedskip) {
buff = malloc(rq->decodedlength);
@@ -485,7 +480,7 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
dest = buff;
}
- if (rq->partial_decoding || !support_0padding)
+ if (rq->partial_decoding)
ret = LZ4_decompress_safe_partial(src + inputmargin, dest,
rq->inputsize - inputmargin,
rq->decodedlength, rq->decodedlength);
@@ -589,7 +584,10 @@ static int z_erofs_load_lz4_config(struct erofs_sb_info *sbi,
sbi->lz4.max_pclusterblks = 1; /* reserved case */
} else {
distance = le16_to_cpu(dsb->u1.lz4_max_distance);
+ if (!distance && !erofs_sb_has_lz4_0padding(sbi))
+ return 0;
sbi->lz4.max_pclusterblks = 1;
+ sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
}
sbi->lz4.max_distance = distance;
return 0;
@@ -601,10 +599,8 @@ int z_erofs_parse_cfgs(struct erofs_sb_info *sbi, struct erofs_super_block *dsb)
erofs_off_t offset;
int size, ret = 0;
- if (!erofs_sb_has_compr_cfgs(sbi)) {
- sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
+ if (!erofs_sb_has_compr_cfgs(sbi))
return z_erofs_load_lz4_config(sbi, 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) {
--
2.43.5
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] erofs-utils: lib: separate plain and compressed filesystems formally
2026-06-12 2:20 ` [PATCH] erofs-utils: lib: separate plain and compressed filesystems formally Gao Xiang
@ 2026-06-12 8:06 ` Jonathan Calmels
0 siblings, 0 replies; 3+ messages in thread
From: Jonathan Calmels @ 2026-06-12 8:06 UTC (permalink / raw)
To: Gao Xiang; +Cc: linux-erofs, oliver.yang
On Fri, Jun 12, 2026 at 10:20:01AM +0800, Gao Xiang wrote:
> External email: Use caution opening links or attachments
>
>
> Source kernel commit: 7cef3c8341940febf75db6c25199cd83fb74d52f
>
> !lz4_0padding is simply an ancient layout which is mainly used for
> Linux kernels < 5.3 (prior to the initial EROFS formal version) and
> generated with the option `-Elegacy-compress` by mkfs.erofs between
> 1.0 and 1.8.x.
>
> So recently Linux 7.0+ kernels simply use lz4_0padding as another
> indicator of whether it's an (LZ4) compressed filesystem. Follow
> the new behavior for erofs-utils too to fix an incremental data
> build issue [1].
>
> Reported-by: Jonathan Calmels <jcalmels@nvidia.com>
> [1] https://lore.kernel.org/r/20260611235404.1620899-1-jcalmels@nvidia.com
> Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
> ---
> Hi Jonathan,
>
> Could you confirm if this issue works for you?
>
> Thanks,
> Gao Xiang
>
Yes this approach works too, thanks!
> lib/decompress.c | 20 ++++++++------------
> 1 file changed, 8 insertions(+), 12 deletions(-)
>
> diff --git a/lib/decompress.c b/lib/decompress.c
> index d23135e0cd43..e6d14f4cbd94 100644
> --- a/lib/decompress.c
> +++ b/lib/decompress.c
> @@ -466,17 +466,12 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
> char *dest = rq->out;
> char *src = rq->in;
> char *buff = NULL;
> - bool support_0padding = false;
> unsigned int inputmargin = 0;
> struct erofs_sb_info *sbi = rq->sbi;
>
> - if (erofs_sb_has_lz4_0padding(sbi)) {
> - support_0padding = true;
> -
> - inputmargin = z_erofs_fixup_insize((u8 *)src, rq->inputsize);
> - if (inputmargin >= rq->inputsize)
> - return -EFSCORRUPTED;
> - }
> + inputmargin = z_erofs_fixup_insize((u8 *)src, rq->inputsize);
> + if (inputmargin >= rq->inputsize)
> + return -EFSCORRUPTED;
>
> if (rq->decodedskip) {
> buff = malloc(rq->decodedlength);
> @@ -485,7 +480,7 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
> dest = buff;
> }
>
> - if (rq->partial_decoding || !support_0padding)
> + if (rq->partial_decoding)
> ret = LZ4_decompress_safe_partial(src + inputmargin, dest,
> rq->inputsize - inputmargin,
> rq->decodedlength, rq->decodedlength);
> @@ -589,7 +584,10 @@ static int z_erofs_load_lz4_config(struct erofs_sb_info *sbi,
> sbi->lz4.max_pclusterblks = 1; /* reserved case */
> } else {
> distance = le16_to_cpu(dsb->u1.lz4_max_distance);
> + if (!distance && !erofs_sb_has_lz4_0padding(sbi))
> + return 0;
> sbi->lz4.max_pclusterblks = 1;
> + sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
> }
> sbi->lz4.max_distance = distance;
> return 0;
> @@ -601,10 +599,8 @@ int z_erofs_parse_cfgs(struct erofs_sb_info *sbi, struct erofs_super_block *dsb)
> erofs_off_t offset;
> int size, ret = 0;
>
> - if (!erofs_sb_has_compr_cfgs(sbi)) {
> - sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
> + if (!erofs_sb_has_compr_cfgs(sbi))
> return z_erofs_load_lz4_config(sbi, 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) {
> --
> 2.43.5
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-12 8:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-11 23:54 [PATCH] erofs-utils: lib: fix null deref on incremental uncompressed builds Jonathan Calmels
2026-06-12 2:20 ` [PATCH] erofs-utils: lib: separate plain and compressed filesystems formally Gao Xiang
2026-06-12 8:06 ` Jonathan Calmels
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.