[PATCH v1 2/2] test/py: test kernel_noload decompression buffer overflow
Aristo Chen
aristo.chen at canonical.com
Wed May 20 06:45:51 CEST 2026
Add a sandbox test that builds a FIT containing a compressed
kernel_noload kernel whose uncompressed size far exceeds four times its
compressed size. bootm_load_os() sizes the decompression buffer to
ALIGN(image_len * 4, SZ_1M), so such an image must be rejected with a
decompression error rather than overflowing the buffer.
The test verifies that 'bootm loados' reports the failure instead of
decompressing past the end of the buffer.
Signed-off-by: Aristo Chen <aristo.chen at canonical.com>
---
test/py/tests/test_fit.py | 84 +++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py
index 4f56a1421e1..04e10c33046 100755
--- a/test/py/tests/test_fit.py
+++ b/test/py/tests/test_fit.py
@@ -117,6 +117,36 @@ host save hostfs 0 %(loadables1_addr)x %(loadables1_out)s %(loadables1_size)x
host save hostfs 0 %(loadables2_addr)x %(loadables2_out)s %(loadables2_size)x
'''
+# A minimal ITS for a compressed 'kernel_noload' kernel. bootm allocates its
+# own decompression buffer for this image type, sized to 4x the compressed
+# length; see test_fit_kernel_noload_decomp_overflow().
+NOLOAD_ITS = '''
+/dts-v1/;
+
+/ {
+ description = "FIT with a compressed kernel_noload image";
+ #address-cells = <1>;
+
+ images {
+ kernel-1 {
+ data = /incbin/("%(kernel)s");
+ type = "kernel_noload";
+ arch = "sandbox";
+ os = "linux";
+ compression = "gzip";
+ load = <0>;
+ entry = <0>;
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ kernel = "kernel-1";
+ };
+ };
+};
+'''
+
@pytest.mark.boardspec('sandbox')
@pytest.mark.buildconfigspec('fit')
@pytest.mark.requiredtool('dtc')
@@ -426,3 +456,57 @@ class TestFitImage:
output = ubman.run_command_list(cmds)
assert "can't get kernel image!" in '\n'.join(output)
+
+ def test_fit_kernel_noload_decomp_overflow(self, ubman, fsetup):
+ """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
+ decompressor by that buffer. A kernel that decompresses to far more
+ than four times its compressed size must therefore fail with a
+ decompression error instead of overflowing the buffer.
+ """
+ sz_1m = 1 << 20
+
+ # CONFIG_SYS_BOOTM_LEN is the global decompression limit. Keep the
+ # uncompressed size below it, so the failure is forced by the smaller
+ # per-image kernel_noload buffer rather than by that global limit.
+ 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
+ # than the uncompressed image.
+ decomp_size = 4 * sz_1m
+ kernel = fit_util.make_fname(ubman, 'test-noload-kernel.bin')
+ with open(kernel, 'wb') as fd:
+ fd.write(b'\0' * decomp_size)
+ 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
+ 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))
+
+ fit = fit_util.make_fit(ubman, fsetup['mkimage'], NOLOAD_ITS,
+ {'kernel': kernel_gz})
+ fit_addr = fsetup['fit_addr']
+
+ ubman.run_command_list([
+ 'host load hostfs 0 %x %s' % (fit_addr, fit),
+ 'bootm start %x' % fit_addr,
+ ])
+
+ # 'bootm loados' decompresses the kernel. Decompression must stop at
+ # the buffer boundary and report 'Image too large', which resets the
+ # board; it must not run past the buffer and return to the prompt.
+ ubman.run_command('bootm loados', wait_for_prompt=False)
+ matched = ubman.p.expect(['Image too large', ubman.prompt_compiled])
+
+ # The decompression failure resets the board; bring up a fresh
+ # instance so later tests start from a clean console.
+ ubman.restart_uboot()
+
+ assert matched == 0, \
+ "'bootm loados' did not reject a kernel_noload image whose " \
+ 'decompressed size overflows its decompression buffer'
--
2.43.0
More information about the U-Boot
mailing list