* [PATCH] lib: decompress_unlz4: drop redundant -4 in wrapper call to unlz4
@ 2026-06-13 5:12 Johannes Schneider
2026-06-13 9:37 ` SCHNEIDER Johannes
0 siblings, 1 reply; 3+ messages in thread
From: Johannes Schneider @ 2026-06-13 5:12 UTC (permalink / raw)
To: barebox; +Cc: Johannes Schneider
decompress_unlz4() passes in_len - 4 to unlz4(), as if the caller had
already stripped the LZ4 legacy frame magic from the buffer. But unlz4()
reads the magic itself from buf[0..3] and, in the buffer-input path,
explicitly accounts for it via:
if (!fill) {
inp += 4;
size -= 4;
}
So the magic is subtracted twice from the running size counter. After
the last chunk is consumed, the counter underflows to -4 instead of 0,
which trips the "data corrupted" check at the end of the chunk loop:
if (!fill) {
size -= chunksize;
if (size == 0)
break;
else if (size < 0) {
error("data corrupted");
goto exit_2;
}
inp += chunksize;
}
The bug is benign in practice — by the time the size check fires, all
chunks have already been successfully decompressed and flushed, and ret
holds the 0 returned by the last lz4_decompress_unknownoutputsize()
call. unlz4() returns 0 and the caller treats the operation as
successful, but a spurious "data corrupted" line is printed on every
LZ4 decompression. With pr_fmt set by image-fit.c, FIT-image kernel
boots show:
ERROR: FIT: data corrupted
right between the configuration line and the cmdline-append line.
Pass in_len through unchanged. unlz4() handles the magic itself in both
the input and fill paths.
Fill-mode callers (e.g. uncompress_fd_to_fd) are unaffected: they pass
in_len=0, and unlz4() overwrites the initial size on the first fill()
call.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com>
---
lib/decompress_unlz4.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c
index 2bb30e71bb..17bb4e5de7 100644
--- a/lib/decompress_unlz4.c
+++ b/lib/decompress_unlz4.c
@@ -209,6 +209,6 @@ STATIC int decompress_unlz4(unsigned char *buf, long in_len,
void(*error)(char *x)
)
{
- return unlz4(buf, in_len - 4, fill, flush, output, posp, error);
+ return unlz4(buf, in_len, fill, flush, output, posp, error);
}
#define decompress decompress_unlz4
base-commit: 6c70fb327d486376c1f2e37dfff2212cb9eebb1b
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] lib: decompress_unlz4: drop redundant -4 in wrapper call to unlz4 2026-06-13 5:12 [PATCH] lib: decompress_unlz4: drop redundant -4 in wrapper call to unlz4 Johannes Schneider @ 2026-06-13 9:37 ` SCHNEIDER Johannes 2026-06-15 10:00 ` Ahmad Fatoum 0 siblings, 1 reply; 3+ messages in thread From: SCHNEIDER Johannes @ 2026-06-13 9:37 UTC (permalink / raw) To: barebox Hoi, please disregard this patch :-S i've since found out that the root cause lies in the way we build lz4 compressed fitimage parts - there a plain lz4 call, with no 4-byte size trailer is used. And this missing trailer is what triggered the "Error: Fit: data corrupted" - which is non fatal anyway, as the system still booted. Now i'm wondering why barebox is using this (legacy?) format? gruß Johannes ________________________________________ From: Johannes Schneider <johannes.schneider@leica-geosystems.com> Sent: Saturday, June 13, 2026 07:12 To: barebox@lists.infradead.org Cc: SCHNEIDER Johannes Subject: [PATCH] lib: decompress_unlz4: drop redundant -4 in wrapper call to unlz4 decompress_unlz4() passes in_len - 4 to unlz4(), as if the caller had already stripped the LZ4 legacy frame magic from the buffer. But unlz4() reads the magic itself from buf[0..3] and, in the buffer-input path, explicitly accounts for it via: if (!fill) { inp += 4; size -= 4; } So the magic is subtracted twice from the running size counter. After the last chunk is consumed, the counter underflows to -4 instead of 0, which trips the "data corrupted" check at the end of the chunk loop: if (!fill) { size -= chunksize; if (size == 0) break; else if (size < 0) { error("data corrupted"); goto exit_2; } inp += chunksize; } The bug is benign in practice — by the time the size check fires, all chunks have already been successfully decompressed and flushed, and ret holds the 0 returned by the last lz4_decompress_unknownoutputsize() call. unlz4() returns 0 and the caller treats the operation as successful, but a spurious "data corrupted" line is printed on every LZ4 decompression. With pr_fmt set by image-fit.c, FIT-image kernel boots show: ERROR: FIT: data corrupted right between the configuration line and the cmdline-append line. Pass in_len through unchanged. unlz4() handles the magic itself in both the input and fill paths. Fill-mode callers (e.g. uncompress_fd_to_fd) are unaffected: they pass in_len=0, and unlz4() overwrites the initial size on the first fill() call. Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com> --- lib/decompress_unlz4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c index 2bb30e71bb..17bb4e5de7 100644 --- a/lib/decompress_unlz4.c +++ b/lib/decompress_unlz4.c @@ -209,6 +209,6 @@ STATIC int decompress_unlz4(unsigned char *buf, long in_len, void(*error)(char *x) ) { - return unlz4(buf, in_len - 4, fill, flush, output, posp, error); + return unlz4(buf, in_len, fill, flush, output, posp, error); } #define decompress decompress_unlz4 base-commit: 6c70fb327d486376c1f2e37dfff2212cb9eebb1b -- 2.43.0 ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] lib: decompress_unlz4: drop redundant -4 in wrapper call to unlz4 2026-06-13 9:37 ` SCHNEIDER Johannes @ 2026-06-15 10:00 ` Ahmad Fatoum 0 siblings, 0 replies; 3+ messages in thread From: Ahmad Fatoum @ 2026-06-15 10:00 UTC (permalink / raw) To: SCHNEIDER Johannes, barebox Hello, On 6/13/26 11:37 AM, SCHNEIDER Johannes wrote: > Hoi, > > > please disregard this patch :-S > > i've since found out that the root cause lies in the way we build lz4 compressed fitimage parts - there a plain lz4 call, with no 4-byte size trailer is used. And this missing trailer is what triggered the "Error: Fit: data corrupted" - which is non fatal anyway, as the system still booted. > > Now i'm wondering why barebox is using this (legacy?) format? gzip includes the size of the uncompressed data. The kernel decompressors that barebox imports add that field manually for other compression algorithms, whose header format lack it. If you find a way that can accommodate both, we can go with it. Cheers, Ahmad > > > gruß > Johannes > > ________________________________________ > From: Johannes Schneider <johannes.schneider@leica-geosystems.com> > Sent: Saturday, June 13, 2026 07:12 > To: barebox@lists.infradead.org > Cc: SCHNEIDER Johannes > Subject: [PATCH] lib: decompress_unlz4: drop redundant -4 in wrapper call to unlz4 > > decompress_unlz4() passes in_len - 4 to unlz4(), as if the caller had > already stripped the LZ4 legacy frame magic from the buffer. But unlz4() > reads the magic itself from buf[0..3] and, in the buffer-input path, > explicitly accounts for it via: > > if (!fill) { > inp += 4; > size -= 4; > } > > So the magic is subtracted twice from the running size counter. After > the last chunk is consumed, the counter underflows to -4 instead of 0, > which trips the "data corrupted" check at the end of the chunk loop: > > if (!fill) { > size -= chunksize; > if (size == 0) > break; > else if (size < 0) { > error("data corrupted"); > goto exit_2; > } > inp += chunksize; > } > > The bug is benign in practice — by the time the size check fires, all > chunks have already been successfully decompressed and flushed, and ret > holds the 0 returned by the last lz4_decompress_unknownoutputsize() > call. unlz4() returns 0 and the caller treats the operation as > successful, but a spurious "data corrupted" line is printed on every > LZ4 decompression. With pr_fmt set by image-fit.c, FIT-image kernel > boots show: > > ERROR: FIT: data corrupted > > right between the configuration line and the cmdline-append line. > > Pass in_len through unchanged. unlz4() handles the magic itself in both > the input and fill paths. > > Fill-mode callers (e.g. uncompress_fd_to_fd) are unaffected: they pass > in_len=0, and unlz4() overwrites the initial size on the first fill() > call. > > Assisted-by: Claude:claude-opus-4-7 > Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com> > --- > lib/decompress_unlz4.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c > index 2bb30e71bb..17bb4e5de7 100644 > --- a/lib/decompress_unlz4.c > +++ b/lib/decompress_unlz4.c > @@ -209,6 +209,6 @@ STATIC int decompress_unlz4(unsigned char *buf, long in_len, > void(*error)(char *x) > ) > { > - return unlz4(buf, in_len - 4, fill, flush, output, posp, error); > + return unlz4(buf, in_len, fill, flush, output, posp, error); > } > #define decompress decompress_unlz4 > > base-commit: 6c70fb327d486376c1f2e37dfff2212cb9eebb1b > -- > 2.43.0 > > > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-15 10:01 UTC | newest] Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-06-13 5:12 [PATCH] lib: decompress_unlz4: drop redundant -4 in wrapper call to unlz4 Johannes Schneider 2026-06-13 9:37 ` SCHNEIDER Johannes 2026-06-15 10:00 ` Ahmad Fatoum
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox