[PATCH v2 3/3] bootm: increase kernel_noload decompression headroom from 4x to 8x
Aristo Chen
aristo.chen at canonical.com
Wed May 27 17:04:35 CEST 2026
For a compressed kernel_noload image, bootm_load_os() allocates a buffer
of ALIGN(image_len * 4, SZ_1M). The 4x factor is at the edge of what
modern compressors (zstd, xz) achieve on real kernels, so a
well-compressed vendor kernel can fail to boot at runtime with no
intervening warning.
Bump the headroom to 8x. The buffer is still bounded by the compressed
image size, and the SZ_1M alignment keeps the overhead below 1 MiB on
small kernels. Update the matching references in the kernel_noload
sandbox tests so they stay in sync with the bound bootm_load_os()
enforces.
Suggested-by: Simon Glass <sjg at chromium.org>
Signed-off-by: Aristo Chen <aristo.chen at canonical.com>
---
boot/bootm.c | 6 +++---
test/py/tests/test_fit.py | 14 +++++++-------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/boot/bootm.c b/boot/bootm.c
index f9b81bbf794..1d8bd30217f 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -619,14 +619,14 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
/*
* For a "noload" compressed kernel we need to allocate a buffer large
* enough to decompress in to and use that as the load address now.
- * Assume that the kernel compression is at most a factor of 4 since
- * zstd almost achieves that.
+ * Allow up to 8x compression: this comfortably covers what zstd and xz
+ * achieve on real kernels, with headroom for well-compressed payloads.
* Use an alignment of 2MB since this might help arm64
*/
if (os.type == IH_TYPE_KERNEL_NOLOAD && os.comp != IH_COMP_NONE) {
phys_addr_t addr;
- decomp_len = ALIGN(image_len * 4, SZ_1M);
+ decomp_len = ALIGN(image_len * 8, SZ_1M);
err = lmb_alloc_mem(LMB_MEM_ALLOC_ANY, SZ_2M, &addr,
decomp_len, LMB_NONE);
if (err)
diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py
index 560b7513e67..deffadc8b3e 100755
--- a/test/py/tests/test_fit.py
+++ b/test/py/tests/test_fit.py
@@ -461,9 +461,9 @@ class TestFitImage:
"""Test that an over-large compressed kernel_noload image is rejected
For a compressed 'kernel_noload' kernel, bootm_load_os() allocates a
- decompression buffer of ALIGN(image_len * 4, SZ_1M) and must bound the
+ decompression buffer of ALIGN(image_len * 8, SZ_1M) and must bound the
decompressor by that buffer. A kernel that decompresses to far more
- than four times its compressed size must therefore fail with a
+ than eight times its compressed size must therefore fail with a
decompression error instead of overflowing the buffer.
"""
sz_1m = 1 << 20
@@ -474,7 +474,7 @@ class TestFitImage:
bootm_len = int(ubman.config.buildconfig['config_sys_bootm_len'], 0)
# 4MB of zeros compresses to a few KB, so the decompression buffer
- # (ALIGN(image_len * 4, SZ_1M), i.e. 1MB here) ends up far smaller
+ # (ALIGN(image_len * 8, SZ_1M), i.e. 1MB here) ends up far smaller
# than the uncompressed image.
decomp_size = 4 * sz_1m
kernel = fit_util.make_fname(ubman, 'test-noload-kernel.bin')
@@ -483,7 +483,7 @@ class TestFitImage:
kernel_gz = self.make_compressed(ubman, kernel)
image_len = self.filesize(kernel_gz)
- req_size = (image_len * 4 + sz_1m - 1) // sz_1m * sz_1m
+ req_size = (image_len * 8 + sz_1m - 1) // sz_1m * sz_1m
assert req_size < decomp_size <= bootm_len, (
'Test setup error: need decomp buffer (%#x) < image (%#x) <= '
'CONFIG_SYS_BOOTM_LEN (%#x)' % (req_size, decomp_size, bootm_len))
@@ -515,13 +515,13 @@ class TestFitImage:
"""Test that decompression succeeds exactly at the buffer limit
For a compressed 'kernel_noload' kernel, bootm_load_os() allocates a
- decompression buffer of ALIGN(image_len * 4, SZ_1M). A kernel whose
+ decompression buffer of ALIGN(image_len * 8, SZ_1M). A kernel whose
decompressed size equals that buffer exactly must succeed, guarding
against an off-by-one rejection at the buffer limit.
"""
sz_1m = 1 << 20
- # 1MiB of zeros compresses to a few KB, so image_len * 4 rounds up to
+ # 1MiB of zeros compresses to a few KB, so image_len * 8 rounds up to
# exactly 1MiB. Picking decomp_size = 1MiB makes the decompressed size
# match the buffer exactly.
decomp_size = sz_1m
@@ -531,7 +531,7 @@ class TestFitImage:
kernel_gz = self.make_compressed(ubman, kernel)
image_len = self.filesize(kernel_gz)
- req_size = (image_len * 4 + sz_1m - 1) // sz_1m * sz_1m
+ req_size = (image_len * 8 + sz_1m - 1) // sz_1m * sz_1m
assert decomp_size == req_size, (
'Test setup error: need decomp_size (%#x) == req_size (%#x)'
% (decomp_size, req_size))
--
2.43.0
More information about the U-Boot
mailing list