[PATCH 1/2] initrd: fix lz4 decompress with initrd

Sascha Hauer s.hauer at pengutronix.de
Thu May 22 11:59:04 PDT 2025


This is an adoption of the corresponding Linux commit:

| commit 4d4b866aee039d609c0b40e7e5b27204607ce614
| Author: Yinghai Lu <yinghai at kernel.org>
| Date:   Fri Aug 8 14:23:10 2014 -0700
|
| During testing initrd (>2G) support, find decompress/lz4 does not work
| with initrd at all.
|
| decompress_* should support:
| 1. inbuf[]/outbuf[] for kernel preboot.
| 2. inbuf[]/flush() for initramfs
| 3. fill()/flush() for initrd.
|
| in the unlz4 does not handle case 3, as input len is passed as 0, and it
| failed in first try.
|
| Fix that add one extra if (fill) checking, and get out if EOF from the
| fill().
|
| Signed-off-by: Yinghai Lu <yinghai at kernel.org>
| Cc: Kyungsik Lee <kyungsik.lee at lge.com>
| Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
| Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>

In barebox case 3 is used when called from uncompress_fd_to_fd() which
is used in the uncompress command. This seems to never have worked with
LZ4 compressed files.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 lib/decompress_unlz4.c | 65 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 43 insertions(+), 22 deletions(-)

diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c
index a18e6591e9fd1e63158ac58c6d265df4f002fdf5..2bb30e71bb1ca1d73ae20f815f0a2be93d4ea7da 100644
--- a/lib/decompress_unlz4.c
+++ b/lib/decompress_unlz4.c
@@ -90,13 +90,20 @@ static inline int unlz4(u8 *input, long in_len,
 	if (posp)
 		*posp = 0;
 
-	if (fill)
-		fill(inp, 4);
+	if (fill) {
+		size = fill(inp, 4);
+		if (size < 4) {
+			error("data corrupted");
+			goto exit_2;
+		}
+	}
 
 	chunksize = get_unaligned_le32(inp);
 	if (chunksize == ARCHIVE_MAGICNUMBER) {
-		inp += 4;
-		size -= 4;
+		if (!fill) {
+			inp += 4;
+			size -= 4;
+		}
 	} else {
 		error("invalid header");
 		goto exit_2;
@@ -107,29 +114,44 @@ static inline int unlz4(u8 *input, long in_len,
 
 	for (;;) {
 
-		if (fill)
-			fill(inp, 4);
+		if (fill) {
+			size = fill(inp, 4);
+			if (size == 0)
+				break;
+			if (size < 4) {
+				error("data corrupted");
+				goto exit_2;
+			}
+		}
 
 		chunksize = get_unaligned_le32(inp);
 		if (chunksize == ARCHIVE_MAGICNUMBER) {
-			inp += 4;
-			size -= 4;
+			if (!fill) {
+				inp += 4;
+				size -= 4;
+			}
 			if (posp)
 				*posp += 4;
 			continue;
 		}
-		inp += 4;
-		size -= 4;
+
 
 		if (posp)
 			*posp += 4;
 
-		if (fill) {
+		if (!fill) {
+			inp += 4;
+			size -= 4;
+		} else {
 			if (chunksize > lz4_compressbound(uncomp_chunksize)) {
 				error("chunk length is longer than allocated");
 				goto exit_2;
 			}
-			fill(inp, chunksize);
+			size = fill(inp, chunksize);
+			if (size < chunksize) {
+				error("data corrupted");
+				goto exit_2;
+			}
 		}
 #ifdef PREBOOT
 		if (out_len >= uncomp_chunksize) {
@@ -155,18 +177,17 @@ static inline int unlz4(u8 *input, long in_len,
 		if (posp)
 			*posp += chunksize;
 
-		size -= chunksize;
+		if (!fill) {
+			size -= chunksize;
 
-		if (size == 0)
-			break;
-		else if (size < 0) {
-			error("data corrupted");
-			goto exit_2;
+			if (size == 0)
+				break;
+			else if (size < 0) {
+				error("data corrupted");
+				goto exit_2;
+			}
+			inp += chunksize;
 		}
-
-		inp += chunksize;
-		if (fill)
-			inp = inp_start;
 	}
 
 	ret = 0;

-- 
2.39.5




More information about the barebox mailing list