[PATCH v2 1/1] image: fit: Apply overlays using aligned writable FDT copies

Marek Vasut marek.vasut at mailbox.org
Tue Feb 10 21:04:33 CET 2026


On 2/10/26 7:54 PM, James Hilliard wrote:
> libfdt expects FDT/DTO blobs to be 8-byte aligned. When loading the
> base FDT or overlays from a FIT, the mapped buffer may be unaligned,
> which can break fdt_open_into() on strict-alignment architectures.
> 
> boot_get_fdt_fit() relocates the base FDT with boot_relocate_fdt()
> before applying overlays. That uses the bootm memory map and can
> overlap with the FIT buffer when the FIT is loaded into RAM,
> corrupting data needed to load the kernel and ramdisk.
> 
> Allocate writable, 8-byte aligned copies of the base FDT and overlays
> with memalign() and fdt_open_into(). Grow the base buffer as needed,
> apply overlays to it and pack the final tree. Free each temporary
> overlay copy after application and check fdt_pack() errors.
> 
> Fixes: 8fbcc0e0e839 ("boot: Assure FDT is always 8-byte aligned")
> Fixes: 881f0b77dc8c ("image: apply FDTOs on FDT image node")
> Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
> ---
> Changes v1 -> v2:
>    - also fix alignment issues

Please keep the Jamie on CC

> ---
>   boot/image-fit.c | 158 +++++++++++++++++++++++++++++++++++------------
>   1 file changed, 118 insertions(+), 40 deletions(-)
> 
> diff --git a/boot/image-fit.c b/boot/image-fit.c
> index 41ab1f552b0..68fb75c8389 100644
> --- a/boot/image-fit.c
> +++ b/boot/image-fit.c
> @@ -2344,6 +2344,52 @@ int boot_get_setup_fit(struct bootm_headers *images, uint8_t arch,
>   }
>   
>   #ifndef USE_HOSTCC
> +#ifdef CONFIG_OF_LIBFDT_OVERLAY
> +static int boot_get_fdt_fit_into_buffer(const void *src, ulong srclen,
> +					ulong extra, ulong min_dstlen,
> +					void **fdtdstbuf, ulong *fdtdstlenp)
> +{
> +	const void *fdtsrcbuf;
> +	void *tmp = NULL;
> +	ulong fdtdstlen;
> +	int err;
> +
> +	/* Make sure the source FDT/DTO is 8-byte aligned for libfdt. */
> +	fdtsrcbuf = src;
> +	if (!IS_ALIGNED((uintptr_t)src, 8)) {
> +		tmp = memalign(8, srclen);
> +		if (!tmp)
> +			return -ENOMEM;
> +
> +		memcpy(tmp, src, srclen);
> +		fdtsrcbuf = tmp;
> +	}
> +
> +	fdtdstlen = ALIGN(fdt_totalsize(fdtsrcbuf) + extra, SZ_4K);
> +	min_dstlen = ALIGN(min_dstlen, SZ_4K);
> +	if (fdtdstlen < min_dstlen)
> +		fdtdstlen = min_dstlen;
> +
> +	*fdtdstbuf = memalign(8, fdtdstlen);
> +	if (!*fdtdstbuf) {
> +		free(tmp);
> +		return -ENOMEM;
> +	}
> +
> +	err = fdt_open_into(fdtsrcbuf, *fdtdstbuf, fdtdstlen);
> +	free(tmp);
> +	if (err < 0) {
> +		free(*fdtdstbuf);
> +		*fdtdstbuf = NULL;
> +		return err;
> +	}
> +
> +	*fdtdstlenp = fdtdstlen;
> +
> +	return 0;
> +}
> +#endif
> +
>   int boot_get_fdt_fit(struct bootm_headers *images, ulong addr,
>   		     const char **fit_unamep, const char **fit_uname_configp,
>   		     int arch, ulong *datap, ulong *lenp)
> @@ -2356,18 +2402,12 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr,
>   	char *next_config = NULL;
>   	ulong load, len;
>   #ifdef CONFIG_OF_LIBFDT_OVERLAY
> -	ulong ovload, ovlen, ovcopylen;
> +	ulong ovload, ovlen, ovcopylen, need;
>   	const char *uconfig;
>   	const char *uname;
> -	/*
> -	 * of_flat_tree is storing the void * returned by map_sysmem, then its
> -	 * address is passed to boot_relocate_fdt which expects a char ** and it
> -	 * is then cast into a ulong. Setting its type to void * would require
> -	 * to cast its address to char ** when passing it to boot_relocate_fdt.
> -	 * Instead, let's be lazy and use void *.
> -	 */
> -	char *of_flat_tree;
> -	void *base, *ov, *ovcopy = NULL;
> +	void *ovcopy = NULL;
> +	void *base_buf = NULL;
> +	ulong base_buf_size = 0;
>   	int i, err, noffset, ov_noffset;
>   #endif
>   
> @@ -2410,18 +2450,27 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr,
>   	/* we need to apply overlays */
>   
>   #ifdef CONFIG_OF_LIBFDT_OVERLAY
> -	/* Relocate FDT so resizing does not overwrite other data in FIT. */
> -	of_flat_tree = map_sysmem(load, len);
> -	len = ALIGN(fdt_totalsize(load), SZ_4K);
> -	err = boot_relocate_fdt(&of_flat_tree, &len);
> -	if (err) {
> -		printf("Required FDT relocation for applying DTOs failed: %d\n",
> -		       err);
> -		fdt_noffset = -EBADF;
> +	/*
> +	 * Make a writable copy of the base FDT for applying overlays.
> +	 *
> +	 * Do not use boot_relocate_fdt() here: it allocates from the bootm map and
> +	 * may overlap with the FIT buffer (still needed to load the kernel /
> +	 * ramdisk) when the FIT is loaded into RAM.
> +	 */
> +	err = boot_get_fdt_fit_into_buffer(map_sysmem(load, len), len,
> +					   CONFIG_SYS_FDT_PAD, 0, &base_buf,
> +					   &base_buf_size);
> +	if (err < 0) {
> +		if (err == -ENOMEM)
> +			printf("Required FDT copy for applying DTOs failed: out of memory\n");

If this returns ENOMEM, you will likely not be able to print anything, 
so don't bother. Bail with a return value and be done with it, i.e. drop 
the error prints here.

> +		else
> +			printf("Required FDT copy for applying DTOs failed: %s\n",
> +			       fdt_strerror(err));
> +		fdt_noffset = err;
>   		goto out;
>   	}
>   
> -	load = (ulong)of_flat_tree;
> +	len = fdt_off_dt_strings(base_buf) + fdt_size_dt_strings(base_buf);
>   
>   	/* apply extra configs in FIT first, followed by args */
>   	for (i = 1; ; i++) {
> @@ -2465,46 +2514,73 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr,
>   		}
>   		debug("%s loaded at 0x%08lx len=0x%08lx\n",
>   				uname, ovload, ovlen);
> -		ov = map_sysmem(ovload, ovlen);
> -
> -		ovcopylen = ALIGN(fdt_totalsize(ov), SZ_4K);
> -		ovcopy = malloc(ovcopylen);
> -		if (!ovcopy) {
> -			printf("failed to duplicate DTO before application\n");
> -			fdt_noffset = -ENOMEM;
> -			goto out;
> -		}
> -
> -		err = fdt_open_into(ov, ovcopy, ovcopylen);
> +		err = boot_get_fdt_fit_into_buffer(map_sysmem(ovload, ovlen),
> +						   ovlen, 0, 0, &ovcopy,
> +						   &ovcopylen);
>   		if (err < 0) {
> -			printf("failed on fdt_open_into for DTO\n");
> +			if (err == -ENOMEM)
> +				printf("failed to duplicate DTO before application\n");
> +			else
> +				printf("failed on fdt_open_into for DTO: %s\n",

DTTO

> +				       fdt_strerror(err));
>   			fdt_noffset = err;
>   			goto out;
>   		}
>   
> -		base = map_sysmem(load, len + ovlen);
> -		err = fdt_open_into(base, base, len + ovlen);
> -		if (err < 0) {
> -			printf("failed on fdt_open_into\n");
> -			fdt_noffset = err;
> -			goto out;
> +		/*
> +		 * Ensure the base FDT buffer is open and has enough room for
> +		 * the overlay. Grow it on demand.
> +		 */
> +		need = ALIGN(len + ovcopylen + CONFIG_SYS_FDT_PAD, SZ_4K);
> +		if (need > base_buf_size) {

Doesn't boot_get_fdt_fit_into_buffer() do the necessary 
rounding/alignment/... already , so shouldn't it be enough to simply 
call it here, without this conditional ?

> +			void *new_base;
> +			ulong new_size;
> +
> +			err = boot_get_fdt_fit_into_buffer(base_buf, base_buf_size,
> +							   0, need, &new_base,
> +							   &new_size);
> +			if (err < 0) {
> +				if (err == -ENOMEM)
> +					printf("failed to expand FDT for DTO application\n");
> +				else
> +					printf("failed on fdt_open_into while expanding FDT\n");
> +				fdt_noffset = err;
> +				goto out;
> +			}
> +
> +			free(base_buf);
> +			base_buf = new_base;
> +			base_buf_size = new_size;
>   		}
The rest looks good, thanks !


More information about the U-Boot mailing list