[PATCH v2 1/3] bootm: fix overflow of the noload kernel decompression buffer

Aristo Chen aristo.chen at canonical.com
Wed May 27 17:04:33 CEST 2026


For a compressed kernel_noload image, bootm_load_os() allocates a
decompression buffer sized to ALIGN(image_len * 4, SZ_1M), assuming the
kernel compresses by no more than a factor of four. It then passes
CONFIG_SYS_BOOTM_LEN, rather than the size of that buffer, to
image_decomp() as the output limit. The decompressors honour the limit
they are given, so a kernel that decompresses to more than four times
its compressed size is written past the end of the allocated buffer and
corrupts adjacent memory.

Pass the allocation size to image_decomp() and handle_decomp_error() so
decompression stops at the buffer boundary and fails cleanly when the
image is too large, instead of overflowing. The regular non-noload
paths are unchanged and continue to use CONFIG_SYS_BOOTM_LEN. When the
failure is triggered by the smaller per-image buffer, print a note so
that handle_decomp_error()'s generic advice to increase
CONFIG_SYS_BOOTM_LEN does not mislead the reader.

Fixes: 69544c4fd8b1 ("bootm: Support kernel_noload with compression")
Signed-off-by: Aristo Chen <aristo.chen at canonical.com>
---
 boot/bootm.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/boot/bootm.c b/boot/bootm.c
index 4836d6b2d41..f9b81bbf794 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -610,6 +610,7 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
 	ulong blob_end = os.end;
 	ulong image_start = os.image_start;
 	ulong image_len = os.image_len;
+	ulong decomp_len = CONFIG_SYS_BOOTM_LEN;
 	ulong flush_start = ALIGN_DOWN(load, ARCH_DMA_MINALIGN);
 	bool no_overlap;
 	void *load_buf, *image_buf;
@@ -623,11 +624,11 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
 	 * Use an alignment of 2MB since this might help arm64
 	 */
 	if (os.type == IH_TYPE_KERNEL_NOLOAD && os.comp != IH_COMP_NONE) {
-		ulong req_size = ALIGN(image_len * 4, SZ_1M);
 		phys_addr_t addr;
 
+		decomp_len = ALIGN(image_len * 4, SZ_1M);
 		err = lmb_alloc_mem(LMB_MEM_ALLOC_ANY, SZ_2M, &addr,
-				    req_size, LMB_NONE);
+				    decomp_len, LMB_NONE);
 		if (err)
 			return 1;
 
@@ -635,17 +636,20 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
 		images->os.load = (ulong)addr;
 		images->ep = (ulong)addr;
 		debug("Allocated %lx bytes at %lx for kernel (size %lx) decompression\n",
-		      req_size, load, image_len);
+		      decomp_len, load, image_len);
 	}
 
 	load_buf = map_sysmem(load, 0);
 	image_buf = map_sysmem(os.image_start, image_len);
 	err = image_decomp(os.comp, load, os.image_start, os.type,
 			   load_buf, image_buf, image_len,
-			   CONFIG_SYS_BOOTM_LEN, &load_end);
+			   decomp_len, &load_end);
 	if (err) {
 		err = handle_decomp_error(os.comp, load_end - load,
-					  CONFIG_SYS_BOOTM_LEN, err);
+					  decomp_len, err);
+		if (decomp_len != CONFIG_SYS_BOOTM_LEN)
+			printf("Note: noload decompression buffer is %#lx bytes (not CONFIG_SYS_BOOTM_LEN)\n",
+			       decomp_len);
 		bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
 		return err;
 	}
-- 
2.43.0



More information about the U-Boot mailing list