[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