* [PATCH v1 0/2] erofs-utils: lib: fix ZSTD decompression safety issues
@ 2026-03-16 21:28 Utkal Singh
2026-03-16 21:28 ` [PATCH v1 1/2] erofs-utils: lib: validate ZSTD frame content size in decompression Utkal Singh
2026-03-16 21:28 ` [PATCH v1 2/2] erofs-utils: lib: return error on ZSTD decompression length mismatch Utkal Singh
0 siblings, 2 replies; 5+ messages in thread
From: Utkal Singh @ 2026-03-16 21:28 UTC (permalink / raw)
To: linux-erofs; +Cc: hsiangkao, yifan.yfzhao, singhutkal015
This series fixes two issues in z_erofs_decompress_zstd() that can
be triggered by crafted EROFS filesystem images during extraction
(fsck.erofs) or FUSE mounting (erofsfuse).
Patch 1/2 adds validation for the ZSTD frame content size read from
on-disk compressed data. The frame content size (from the ZSTD frame
header) and the decoded length (from the extent map via
z_erofs_map_blocks_iter()) are independent metadata sources. A crafted
image can set them to inconsistent values, causing the output memcpy
to read beyond the decompressed buffer. The legacy
ZSTD_getDecompressedSize() fallback path is also fixed to reject
zero-sized frames.
Patch 2/2 fixes a missing error return when ZSTD decompression
produces a different number of bytes than expected. Without this,
the positive return value passes the caller's error check and
silently returns corrupted data.
Utkal Singh (2):
erofs-utils: lib: validate ZSTD frame content size in decompression
erofs-utils: lib: return error on ZSTD decompression length mismatch
lib/decompress.c | 8 ++++++++
1 file changed, 8 insertions(+)
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 1/2] erofs-utils: lib: validate ZSTD frame content size in decompression
2026-03-16 21:28 [PATCH v1 0/2] erofs-utils: lib: fix ZSTD decompression safety issues Utkal Singh
@ 2026-03-16 21:28 ` Utkal Singh
2026-03-17 2:10 ` Gao Xiang
2026-03-16 21:28 ` [PATCH v1 2/2] erofs-utils: lib: return error on ZSTD decompression length mismatch Utkal Singh
1 sibling, 1 reply; 5+ messages in thread
From: Utkal Singh @ 2026-03-16 21:28 UTC (permalink / raw)
To: linux-erofs; +Cc: hsiangkao, yifan.yfzhao, singhutkal015
ZSTD_getFrameContentSize() reads the content size from the ZSTD
frame header in the compressed data. This is untrusted on-disk
metadata, independent from the extent map that provides
rq->decodedlength via z_erofs_map_blocks_iter().
A crafted EROFS image can set the extent map to claim a decoded
length larger than the actual ZSTD frame content size. When this
happens, a buffer of the (smaller) frame content size is allocated
and decompressed into, but the subsequent memcpy copies
rq->decodedlength bytes from it — a potential out-of-bounds read.
Additionally, the ZSTD_getDecompressedSize() legacy fallback
returns 0 for frames without a content size field. This leads to
malloc(0) followed by out-of-bounds access on the returned pointer.
Reject frames where the reported content size is zero or smaller
than the expected decoded length.
Signed-off-by: Utkal Singh <singhutkal015@gmail.com>
---
lib/decompress.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lib/decompress.c b/lib/decompress.c
index 3e7a173..fb81039 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -48,7 +48,14 @@ static int z_erofs_decompress_zstd(struct z_erofs_decompress_req *rq)
#else
total = ZSTD_getDecompressedSize(src + inputmargin,
rq->inputsize - inputmargin);
+ if (!total)
+ return -EFSCORRUPTED;
#endif
+ if (total < rq->decodedlength) {
+ erofs_err("ZSTD frame content size %llu < decoded length %u",
+ total, rq->decodedlength);
+ return -EFSCORRUPTED;
+ }
if (rq->decodedskip || total != rq->decodedlength) {
buff = malloc(total);
if (!buff)
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v1 2/2] erofs-utils: lib: return error on ZSTD decompression length mismatch
2026-03-16 21:28 [PATCH v1 0/2] erofs-utils: lib: fix ZSTD decompression safety issues Utkal Singh
2026-03-16 21:28 ` [PATCH v1 1/2] erofs-utils: lib: validate ZSTD frame content size in decompression Utkal Singh
@ 2026-03-16 21:28 ` Utkal Singh
1 sibling, 0 replies; 5+ messages in thread
From: Utkal Singh @ 2026-03-16 21:28 UTC (permalink / raw)
To: linux-erofs; +Cc: hsiangkao, yifan.yfzhao, singhutkal015
When ZSTD_decompress() succeeds but produces a different number of
bytes than expected, the code logs an error and jumps to cleanup.
However, it does not set ret to an error code. Since ret still
holds the positive ZSTD output size, the caller treats it as
success via the 'if (ret < 0)' check in z_erofs_read_one_data(),
causing silently corrupted data to be returned.
Set ret to -EIO before jumping to cleanup, consistent with the
ZSTD_isError() error handling path above.
Signed-off-by: Utkal Singh <singhutkal015@gmail.com>
---
lib/decompress.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/decompress.c b/lib/decompress.c
index fb81039..a27881c 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -75,6 +75,7 @@ static int z_erofs_decompress_zstd(struct z_erofs_decompress_req *rq)
if (ret != (int)total) {
erofs_err("ZSTD decompress length mismatch %d, expected %d",
ret, total);
+ ret = -EIO;
goto out;
}
if (rq->decodedskip || total != rq->decodedlength)
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v1 1/2] erofs-utils: lib: validate ZSTD frame content size in decompression
2026-03-16 21:28 ` [PATCH v1 1/2] erofs-utils: lib: validate ZSTD frame content size in decompression Utkal Singh
@ 2026-03-17 2:10 ` Gao Xiang
2026-03-17 4:47 ` Utkal Singh
0 siblings, 1 reply; 5+ messages in thread
From: Gao Xiang @ 2026-03-17 2:10 UTC (permalink / raw)
To: Utkal Singh, linux-erofs; +Cc: yifan.yfzhao
On 2026/3/17 05:28, Utkal Singh wrote:
> ZSTD_getFrameContentSize() reads the content size from the ZSTD
> frame header in the compressed data. This is untrusted on-disk
> metadata, independent from the extent map that provides
> rq->decodedlength via z_erofs_map_blocks_iter().
>
> A crafted EROFS image can set the extent map to claim a decoded
> length larger than the actual ZSTD frame content size. When this
> happens, a buffer of the (smaller) frame content size is allocated
> and decompressed into, but the subsequent memcpy copies
> rq->decodedlength bytes from it — a potential out-of-bounds read.
>
> Additionally, the ZSTD_getDecompressedSize() legacy fallback
> returns 0 for frames without a content size field. This leads to
> malloc(0) followed by out-of-bounds access on the returned pointer.
>
> Reject frames where the reported content size is zero or smaller
> than the expected decoded length.
For this kind of commits, please add reproduciable way all the time.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v1 1/2] erofs-utils: lib: validate ZSTD frame content size in decompression
2026-03-17 2:10 ` Gao Xiang
@ 2026-03-17 4:47 ` Utkal Singh
0 siblings, 0 replies; 5+ messages in thread
From: Utkal Singh @ 2026-03-17 4:47 UTC (permalink / raw)
To: Gao Xiang; +Cc: linux-erofs, yifan.yfzhao
[-- Attachment #1: Type: text/plain, Size: 1424 bytes --]
Hi Gao Xiang,
Thank you for the review.
Understood, I will include a reproducible way in v2 for both patches.
I have also created a GitHub issue to track these patches:
https://github.com/erofs/erofs-utils/issues/47
v2 will follow shortly.
Best regards,
Utkal Singh
On Tue, 17 Mar 2026 at 07:40, Gao Xiang <hsiangkao@linux.alibaba.com> wrote:
>
>
> On 2026/3/17 05:28, Utkal Singh wrote:
> > ZSTD_getFrameContentSize() reads the content size from the ZSTD
> > frame header in the compressed data. This is untrusted on-disk
> > metadata, independent from the extent map that provides
> > rq->decodedlength via z_erofs_map_blocks_iter().
> >
> > A crafted EROFS image can set the extent map to claim a decoded
> > length larger than the actual ZSTD frame content size. When this
> > happens, a buffer of the (smaller) frame content size is allocated
> > and decompressed into, but the subsequent memcpy copies
> > rq->decodedlength bytes from it — a potential out-of-bounds read.
> >
> > Additionally, the ZSTD_getDecompressedSize() legacy fallback
> > returns 0 for frames without a content size field. This leads to
> > malloc(0) followed by out-of-bounds access on the returned pointer.
> >
> > Reject frames where the reported content size is zero or smaller
> > than the expected decoded length.
>
> For this kind of commits, please add reproduciable way all the time.
>
[-- Attachment #2: Type: text/html, Size: 1931 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-17 4:47 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-16 21:28 [PATCH v1 0/2] erofs-utils: lib: fix ZSTD decompression safety issues Utkal Singh
2026-03-16 21:28 ` [PATCH v1 1/2] erofs-utils: lib: validate ZSTD frame content size in decompression Utkal Singh
2026-03-17 2:10 ` Gao Xiang
2026-03-17 4:47 ` Utkal Singh
2026-03-16 21:28 ` [PATCH v1 2/2] erofs-utils: lib: return error on ZSTD decompression length mismatch Utkal Singh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox