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 <[email protected]> --- 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

