[PATCH] erofs-utils: lib: validate decodedskip in z_erofs_decompress()

Utkal Singh singhutkal015 at gmail.com
Tue Mar 17 07:55:49 AEDT 2026


The INTERLACED and SHIFTED paths in z_erofs_decompress() guard against
decodedskip exceeding decodedlength, but the compressed backends --
LZ4, LZMA, deflate, zstd -- all perform:

  memcpy(rq->out, dest + rq->decodedskip,
         rq->decodedlength - rq->decodedskip);

without the same check.  Both fields are unsigned int, so when
decodedskip > decodedlength the subtraction wraps to ~4 GiB, causing
a heap buffer overflow in every affected backend.

A crafted EROFS image with inconsistent compressed extent mapping can
cause z_erofs_read_one_data() to pass a skip value that exceeds the
logical extent length.  This affects all library consumers: erofsfuse,
dump.erofs, fsck.erofs, and the rebuild path.

Add an early validation ensuring decodedskip does not exceed
decodedlength before any algorithm dispatch, so all decompression
paths are uniformly protected.

Signed-off-by: Utkal Singh <singhutkal015 at gmail.com>
---
 lib/decompress.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/decompress.c b/lib/decompress.c
index 3e7a173..e102292 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -511,6 +511,13 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq)
 {
 	struct erofs_sb_info *sbi = rq->sbi;
 
+	/* reject decodedskip exceeding decodedlength to avoid underflow */
+	if (rq->decodedlength < rq->decodedskip) {
+		erofs_err("bogus decodedskip %u > decodedlength %u",
+			  rq->decodedskip, rq->decodedlength);
+		return -EFSCORRUPTED;
+	}
+
 	if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
 		unsigned int count, rightpart, skip;
 
-- 
2.43.0



More information about the Linux-erofs mailing list