Add SPL_FIT_CIPHER and decrypt FIT image data before post-processing, decompression or moving it to the final load address.
SPL cannot always allocate a new output buffer while loading FIT images, so use the caller-provided decrypt-to-buffer helper. External encrypted images are read into scratch memory first, then decrypted either in-place for compressed payloads or into a non-overlapping buffer for direct loads. Embedded encrypted images decrypt into the final load buffer or a scratch buffer when decompression is still required. Signed-off-by: James Hilliard <[email protected]> --- boot/Kconfig | 9 +++++ boot/image-fit.c | 2 +- common/spl/spl_fit.c | 92 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index 8e468c56176..19bbeb9ad36 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -155,6 +155,15 @@ config FIT_CIPHER Enable the feature of data ciphering/unciphering in the tool mkimage and in the u-boot support of the FIT image. +config SPL_FIT_CIPHER + bool "Enable ciphering data in SPL FIT images" + depends on SPL_LOAD_FIT + depends on SPL_DM_AES + select SPL_FIT + help + Enable unciphering of FIT image data in SPL. This allows SPL to + decrypt an encrypted U-Boot proper FIT image through an AES driver. + config FIT_VERITY bool "dm-verity boot parameter generation from FIT metadata" depends on FIT && OF_LIBFDT diff --git a/boot/image-fit.c b/boot/image-fit.c index dac8b35f338..1d1723bdae0 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -2290,7 +2290,7 @@ int fit_image_load(struct bootm_headers *images, ulong addr, } /* Decrypt data before uncompress/move */ - if (IS_ENABLED(CONFIG_FIT_CIPHER) && IMAGE_ENABLE_DECRYPT) { + if (!tools_build() && IMAGE_ENABLE_DECRYPT) { puts(" Decrypting Data ... "); if (fit_image_uncipher(fit, noffset, &buf, &size)) { puts("Error\n"); diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index d89384449b3..57975a7638f 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -16,6 +16,7 @@ #include <sysinfo.h> #include <asm/global_data.h> #include <asm/io.h> +#include <limits.h> #include <linux/libfdt.h> #include <linux/printk.h> @@ -193,6 +194,47 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size, return ALIGN(data_size, spl_get_bl_len(info)); } +static int spl_fit_image_decrypt(const void *fit, int node, int cipher_node, + void **data, size_t *size, void *dst) +{ + size_t dst_size; + int ret; + + puts(" Decrypting Data ... "); + ret = fit_image_decrypt_data_to(fit, node, cipher_node, *data, *size, + dst, &dst_size); + if (ret) { + puts("Error\n"); + return ret; + } + + *data = dst; + *size = dst_size; + + puts("OK\n"); + + return 0; +} + +static bool spl_fit_ranges_overlap(ulong addr1, size_t size1, + ulong addr2, size_t size2) +{ + ulong end1, end2; + + if (!size1 || !size2) + return false; + + end1 = addr1 + size1; + if (end1 < addr1) + end1 = ULONG_MAX; + + end2 = addr2 + size2; + if (end2 < addr2) + end2 = ULONG_MAX; + + return addr1 < end2 && addr2 < end1; +} + /** * load_simple_fit(): load the image described in a certain FIT node * @info: points to information about the device to load data from @@ -225,12 +267,15 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, const void *data; const void *fit = ctx->fit; bool external_data = false; + bool encrypted; + bool needs_decomp = false; + int cipher_node = -ENOENT; + int ret; log_debug("starting\n"); if (CONFIG_IS_ENABLED(BOOTMETH_VBE) && xpl_get_phase(info) != IH_PHASE_NONE) { enum image_phase_t phase; - int ret; ret = fit_image_get_phase(fit, node, &phase); /* if the image is for any phase, let's use it */ @@ -256,6 +301,8 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, if (spl_decompression_enabled()) { fit_image_get_comp(fit, node, &image_comp); debug("%s ", genimg_get_comp_name(image_comp)); + needs_decomp = image_comp == IH_COMP_GZIP || + image_comp == IH_COMP_LZMA; } if (fit_image_get_load(fit, node, &load_addr)) { @@ -267,6 +314,10 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, load_addr = image_info->load_addr; } + if (CONFIG_IS_ENABLED(FIT_CIPHER)) + cipher_node = fdt_subnode_offset(fit, node, FIT_CIPHER_NODENAME); + encrypted = cipher_node >= 0; + if (!fit_image_get_data_position(fit, node, &offset)) { external_data = true; } else if (!fit_image_get_data_offset(fit, node, &offset)) { @@ -291,11 +342,12 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, return 0; } - if (spl_decompression_enabled() && - (image_comp == IH_COMP_GZIP || image_comp == IH_COMP_LZMA)) - src_ptr = map_sysmem(ALIGN(CONFIG_SYS_LOAD_ADDR, ARCH_DMA_MINALIGN), len); + if (needs_decomp || encrypted) + src_ptr = map_sysmem(ALIGN(CONFIG_SYS_LOAD_ADDR, + ARCH_DMA_MINALIGN), len); else - src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN), len); + src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN), + len); length = len; overhead = get_aligned_image_overhead(info, offset); @@ -331,10 +383,38 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, puts("OK\n"); } + load_ptr = map_sysmem(load_addr, length); + if (encrypted) { + void *decrypt_ptr; + + if (needs_decomp) { + if (external_data) + decrypt_ptr = src; + else + decrypt_ptr = map_sysmem(ALIGN(CONFIG_SYS_LOAD_ADDR, + ARCH_DMA_MINALIGN), + length); + } else if (external_data) { + if (spl_fit_ranges_overlap((ulong)load_ptr, length, + (ulong)src, length)) + decrypt_ptr = map_sysmem(ALIGN((ulong)src + length, + ARCH_DMA_MINALIGN), + length); + else + decrypt_ptr = load_ptr; + } else { + decrypt_ptr = load_ptr; + } + + ret = spl_fit_image_decrypt(fit, node, cipher_node, &src, &length, + decrypt_ptr); + if (ret) + return ret; + } + if (CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS)) board_fit_image_post_process(fit, node, &src, &length); - load_ptr = map_sysmem(load_addr, length); if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) { size = length; if (gunzip(load_ptr, CONFIG_SYS_BOOTM_LEN, src, &size)) { -- 2.53.0

