From cafe3d6e90e661bd9d42b19f1e2d891da48f3fce Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 16 May 2026 00:37:52 +0100 Subject: boot: fit: support generating DM verity cmdline parameters Add fit_verity_build_cmdline(): when a FILESYSTEM loadable carries a dm-verity subnode, construct the dm-mod.create= kernel cmdline parameter from the verity metadata (block-size, data-blocks, algo, root-hash, salt) and append it to bootargs. Also add dm-mod.waitfor=/dev/fit0[,/dev/fitN] for each dm-verity device so the kernel waits for the underlying FIT block device to appear before setting up device-mapper targets. This is needed when the block driver probes late, e.g. because it depends on NVMEM calibration data. The dm-verity target references /dev/fitN where N is the loadable's index in the configuration -- matching the order Linux's FIT block driver assigns block devices. hash-start-block is read directly from the FIT dm-verity node; mkimage ensures its value equals num-data-blocks by invoking veritysetup with --no-superblock. Signed-off-by: Daniel Golle Reviewed-by: Simon Glass --- boot/bootm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index 4836d6b2d41..ec74873b503 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -243,6 +243,13 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images, static int bootm_start(void) { + /* + * Free dm-verity allocations from a prior boot attempt before + * zeroing the structure. The pointers are guaranteed to be valid + * or NULL: .bss is zero-initialised, and memset() below zeroes + * them again after every boot. + */ + fit_verity_free(&images); memset((void *)&images, 0, sizeof(images)); images.verify = env_get_yesno("verify"); @@ -1071,6 +1078,12 @@ int bootm_run_states(struct bootm_info *bmi, int states) /* For Linux OS do all substitutions at console processing */ if (images->os.os == IH_OS_LINUX) flags = BOOTM_CL_ALL; + ret = fit_verity_apply_bootargs(images); + if (ret) { + printf("dm-verity bootargs failed (err=%d)\n", ret); + ret = CMD_RET_FAILURE; + goto err; + } ret = bootm_process_cmdline_env(flags); if (ret) { printf("Cmdline setup failed (err=%d)\n", ret); -- cgit v1.3.1 From 2ff26c1e37858ba0b2fd12c82e114a3cedcb317a Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Fri, 5 Jun 2026 15:42:49 +0000 Subject: bootm: fix overflow of the noload kernel decompression buffer 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") Reviewed-by: Simon Glass Signed-off-by: Aristo Chen --- boot/bootm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index 4836d6b2d41..b55c41f30b7 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 (os.type == IH_TYPE_KERNEL_NOLOAD && os.comp != IH_COMP_NONE) + printf("Note: noload decompression buffer is %#lx bytes (not CONFIG_SYS_BOOTM_LEN)\n", + decomp_len); bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return err; } -- cgit v1.3.1 From 4956f108539135afb1afdec2b509f62291087d16 Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Fri, 5 Jun 2026 15:42:50 +0000 Subject: bootm: increase kernel_noload decompression headroom from 4x to 8x 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. Suggested-by: Simon Glass Signed-off-by: Aristo Chen --- boot/bootm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index b55c41f30b7..4eee35d7e62 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) -- cgit v1.3.1 From 914ebe8b16b40537c3b438bc213b738151018ec6 Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Fri, 5 Jun 2026 15:42:49 +0000 Subject: bootm: fix overflow of the noload kernel decompression buffer 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") Reviewed-by: Simon Glass Signed-off-by: Aristo Chen --- boot/bootm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index ec74873b503..d0656fbdf08 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -617,6 +617,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; @@ -630,11 +631,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; @@ -642,17 +643,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 (os.type == IH_TYPE_KERNEL_NOLOAD && os.comp != IH_COMP_NONE) + printf("Note: noload decompression buffer is %#lx bytes (not CONFIG_SYS_BOOTM_LEN)\n", + decomp_len); bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return err; } -- cgit v1.3.1 From f42eac9dc8a8b8125920d8a18f7f64afedf1fbc5 Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Fri, 5 Jun 2026 15:42:50 +0000 Subject: bootm: increase kernel_noload decompression headroom from 4x to 8x 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. Suggested-by: Simon Glass Signed-off-by: Aristo Chen --- boot/bootm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index d0656fbdf08..4c260a5f5ce 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -626,14 +626,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) -- cgit v1.3.1 From 3900903a588964555c9e76cca53ada7d217c00f7 Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Fri, 19 Jun 2026 14:45:51 +0000 Subject: bootm: move OS index bound check into the legacy path Commit 103b1e7ce8cc ("bootm: bound-check OS index in bootm_os_get_boot_func()") added a range check to the shared accessor so an out-of-range OS id can no longer drive an out-of-bounds read of boot_os[]. That accessor is reached by every image format, but only a legacy uImage can deliver an unchecked value. bootm_find_os() takes the raw 8-bit ih_os byte straight from image_get_os() for legacy images, whereas the FIT path reaches the accessor only after fit_image_load() has rejected any image whose os is not one of the supported types, and the Android path hardcodes IH_OS_LINUX. The check can therefore never fail for FIT, where it only adds confusion and code. Move the test to the legacy branch of bootm_find_os(), rejecting an out-of-range OS where the untrusted byte enters. This keeps the FIT path clear and lets the check be compiled out when CONFIG_LEGACY_IMAGE_FORMAT is disabled. A valid OS id that has no handler is still reported by the existing NULL return path in bootm_run_states(). Suggested-by: Simon Glass Signed-off-by: Aristo Chen Reviewed-by: Simon Glass --- boot/bootm.c | 4 ++++ boot/bootm_os.c | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index 4c260a5f5ce..f9f0b2e918a 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -330,6 +330,10 @@ static int bootm_find_os(const char *cmd_name, const char *addr_fit) images.os.type = image_get_type(os_hdr); images.os.comp = image_get_comp(os_hdr); images.os.os = image_get_os(os_hdr); + if (images.os.os >= IH_OS_COUNT) { + printf("Unsupported OS type %d\n", images.os.os); + return 1; + } images.os.end = image_get_image_end(os_hdr); images.os.load = image_get_load(os_hdr); diff --git a/boot/bootm_os.c b/boot/bootm_os.c index 69aa577a2fc..ae20b555f5c 100644 --- a/boot/bootm_os.c +++ b/boot/bootm_os.c @@ -599,7 +599,5 @@ int boot_selected_os(int state, struct bootm_info *bmi, boot_os_fn *boot_fn) boot_os_fn *bootm_os_get_boot_func(int os) { - if (os < 0 || os >= ARRAY_SIZE(boot_os)) - return NULL; return boot_os[os]; } -- cgit v1.3.1 From 0f890963da2d463dd47ec77ef75b1324cc8064f9 Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Mon, 22 Jun 2026 13:19:31 +0200 Subject: bootm: fix flush_cache() with IH_TYPE_KERNEL_NOLOAD `flush_start` must be set after `load` has been assigned. Fixes: 69544c4fd8b1 ("bootm: Support kernel_noload with compression") Signed-off-by: Nora Schiffer Reviewed-by: Simon Glass --- boot/bootm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index 4c260a5f5ce..7c9a6f82976 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -618,7 +618,7 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress) 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); + ulong flush_start; bool no_overlap; void *load_buf, *image_buf; int err; @@ -663,6 +663,7 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress) /* We need the decompressed image size in the next steps */ images->os.image_len = load_end - load; + flush_start = ALIGN_DOWN(load, ARCH_DMA_MINALIGN); flush_cache(flush_start, ALIGN(load_end, ARCH_DMA_MINALIGN) - flush_start); debug(" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, load_end); -- cgit v1.3.1 From c2abc606653e7eb1e8dbdbaaf1eac392689875ea Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Mon, 22 Jun 2026 13:19:32 +0200 Subject: bootm: warn about load address for IH_TYPE_KERNEL_NOLOAD in FIT The load address is ignored for IH_TYPE_KERNEL_NOLOAD. Instead of failing the boot when none is set, it makes more sense to warn when it *is* set. Signed-off-by: Nora Schiffer Reviewed-by: Simon Glass --- boot/bootm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index 7c9a6f82976..b1cc6fe6c5c 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -371,11 +371,17 @@ static int bootm_find_os(const char *cmd_name, const char *addr_fit) images.os.end = fit_get_end(images.fit_hdr_os); if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os, - &images.os.load)) { + &images.os.load) && + images.os.type != IH_TYPE_KERNEL_NOLOAD) { puts("Can't get image load address!\n"); bootstage_error(BOOTSTAGE_ID_FIT_LOADADDR); return 1; } + if (images.os.load && images.os.type == IH_TYPE_KERNEL_NOLOAD) { + puts("WARNING: load address set for kernel_noload image, ignoring\n"); + images.os.load = 0; + } + break; #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE -- cgit v1.3.1 From c63051237f2bc79838a27473709948408acdf38b Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Mon, 22 Jun 2026 13:19:33 +0200 Subject: bootm: allow omitting entry point for IH_TYPE_KERNEL_NOLOAD For IH_TYPE_KERNEL_NOLOAD, the entry point is given relative to the image start, making 0 a valid default, and for IH_OS_EFI, it is ignored altogether, so it may be preferable to omit it. Signed-off-by: Nora Schiffer Reviewed-by: Simon Glass --- boot/bootm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'boot/bootm.c') diff --git a/boot/bootm.c b/boot/bootm.c index b1cc6fe6c5c..1aeabdd5db1 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -429,7 +429,7 @@ static int bootm_find_os(const char *cmd_name, const char *addr_fit) ret = fit_image_get_entry(images.fit_hdr_os, images.fit_noffset_os, &images.ep); - if (ret) { + if (ret && images.os.type != IH_TYPE_KERNEL_NOLOAD) { puts("Can't get entry point property!\n"); return 1; } -- cgit v1.3.1