Boards using a single legacy U-Boot image should be able to test it over fastboot without changing their image format. Use the shared RAM reader and SPL loader, with the downloaded length limiting header and payload accesses.
Keep legacy support optional and reject compressed images, which this RAM path does not yet support. Reject legacy downloads when SPL FIT signature verification is enabled to prevent bypassing that verification with an unsigned image. Signed-off-by: Carlo Caione <[email protected]> --- common/spl/spl_fastboot_boot.c | 4 ++-- common/spl/spl_ram.c | 32 ++++++++++++++++++++++++++++++++ doc/android/fastboot.rst | 22 +++++++++++++++------- drivers/fastboot/Kconfig | 7 ++++--- include/spl.h | 11 ++++++++++- include/spl_load.h | 2 ++ test/image/spl_fastboot.c | 13 +++++++++++-- 7 files changed, 76 insertions(+), 15 deletions(-) diff --git a/common/spl/spl_fastboot_boot.c b/common/spl/spl_fastboot_boot.c index f52ea83b230..6a765f91cba 100644 --- a/common/spl/spl_fastboot_boot.c +++ b/common/spl/spl_fastboot_boot.c @@ -11,7 +11,7 @@ struct fastboot_image { size_t size; }; -/* The standard fastboot client wraps a FIT in an Android v0 boot image. */ +/* The standard fastboot client wraps non-Android images in a v0 header. */ static int spl_fastboot_unwrap(struct fastboot_image *image) { const struct andr_boot_img_hdr_v0 *hdr = image->data; @@ -54,7 +54,7 @@ int spl_fastboot_load(struct spl_image_info *spl_image) ret = spl_fastboot_unwrap(&image); if (ret) return ret; - return spl_ram_load_fit(spl_image, (void *)image.data, image.size); + return spl_ram_load(spl_image, (void *)image.data, image.size); } /* Sandbox tests the loader directly, without a physical USB boot method. */ diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c index ee588ef4718..43d9bc95516 100644 --- a/common/spl/spl_ram.c +++ b/common/spl/spl_ram.c @@ -14,6 +14,7 @@ #include <log.h> #include <mapmem.h> #include <spl.h> +#include <spl_load.h> #include <linux/libfdt.h> struct spl_ram_image { @@ -48,6 +49,37 @@ int spl_ram_load_fit(struct spl_image_info *spl_image, void *fit, size_t size) return spl_load_simple_fit(spl_image, &load, 0, fit); } +int spl_ram_load(struct spl_image_info *spl_image, void *buf, size_t size) +{ + struct legacy_img_hdr *header = buf; + struct spl_ram_image image = { .data = buf, .size = size }; + struct spl_load_info load; + + /* Require a complete magic word to identify a headered image. */ + if (size < sizeof(header->ih_magic)) + return -EINVAL; + + /* FIT images can contain multiple payloads with separate load addresses. */ + if (image_get_magic(header) == FDT_MAGIC) + return spl_ram_load_fit(spl_image, buf, size); + if (image_get_magic(header) != IH_MAGIC) + return -ENOEXEC; + + /* Legacy images need a complete header and an uncompressed payload. */ + if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) + return -EPERM; + if (!CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) + return -EOPNOTSUPP; + if (size < sizeof(*header) || !image_get_data_size(header) || + image_get_data_size(header) > size - sizeof(*header)) + return -EINVAL; + if (image_get_comp(header) != IH_COMP_NONE) + return -EPROTONOSUPPORT; + + spl_load_init(&load, spl_ram_load_read, &image, 1); + return spl_load(spl_image, NULL, &load, size, 0); +} + #if CONFIG_IS_ENABLED(RAM_SUPPORT) static int spl_ram_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) diff --git a/doc/android/fastboot.rst b/doc/android/fastboot.rst index 9898348c961..73241e717b8 100644 --- a/doc/android/fastboot.rst +++ b/doc/android/fastboot.rst @@ -120,8 +120,8 @@ Reboot commands require ``CONFIG_SPL_FASTBOOT_REBOOT`` and a platform and ``reboot-recovery`` commands also require a platform ``fastboot_set_reboot_flag()`` implementation. -Booting a downloaded FIT from SPL -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Booting a downloaded image from SPL +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Enable ``CONFIG_SPL_FASTBOOT_BOOT`` and include ``BOOT_DEVICE_BOARD`` in the board's SPL boot order. This load method starts the fastboot session itself; @@ -151,11 +151,19 @@ The host can then download and run a U-Boot FIT without flashing it:: | running from RAM | +-----------------------+ -Use a FIT built for the target, including any firmware required by its normal -SPL handoff (for example BL31 or OP-TEE). FIT verification uses the board's -existing SPL configuration. Raw U-Boot binaries are not supported. The loader -accepts a bare FIT or the Android v0 wrapper added by the standard fastboot -client; separate ramdisk and second-stage arguments are not supported. +With ``CONFIG_SPL_LOAD_FIT``, use a FIT built for the target, including any +firmware required by its normal SPL handoff (for example BL31 or OP-TEE). +FIT verification uses the board's existing SPL configuration. +``CONFIG_SPL_LEGACY_IMAGE_FORMAT`` also permits uncompressed legacy U-Boot +images, using their header's load address and entry point. Legacy CRC checks +follow ``CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK``. +With ``CONFIG_SPL_FIT_SIGNATURE``, legacy downloads are rejected to prevent +bypassing FIT verification. +Raw U-Boot binaries are not supported. + +The loader accepts these images directly or inside the Android v0 wrapper +added by the standard fastboot client; separate ramdisk and second-stage +arguments are not supported. Keep the download buffer separate from SPL, its heap and stack, and all FIT load destinations. ``CONFIG_SPL_FASTBOOT_FLASH`` is optional. diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index c2055132ccc..f57b959f0ea 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -68,12 +68,13 @@ config SPL_USB_FUNCTION_FASTBOOT bool config SPL_FASTBOOT_BOOT - bool "Boot FIT images downloaded with fastboot in SPL" + bool "Boot images downloaded with fastboot in SPL" depends on ARM || MIPS || RISCV || SANDBOX - depends on SPL_FASTBOOT && SPL_FRAMEWORK && SPL_LOAD_FIT + depends on SPL_FASTBOOT && SPL_FRAMEWORK + depends on SPL_LOAD_FIT || SPL_LEGACY_IMAGE_FORMAT depends on !SPL_LOAD_FIT_FULL && !SPL_USB_SDP_SUPPORT help - Enable fastboot boot to load a downloaded FIT image through the SPL + Enable fastboot boot to load a downloaded image through the SPL image loader. Boards enter the USB session by selecting BOOT_DEVICE_BOARD in their SPL boot order. diff --git a/include/spl.h b/include/spl.h index 2b12dbb7215..3348b424b54 100644 --- a/include/spl.h +++ b/include/spl.h @@ -999,7 +999,16 @@ int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr); int spl_ram_load_fit(struct spl_image_info *spl_image, void *fit, size_t size); /** - * spl_fastboot_load() - Load a FIT after the fastboot USB session has stopped + * spl_ram_load() - Load a downloaded image from RAM + * @spl_image: Receives the loaded image information + * @buf: Image buffer + * @size: Number of bytes in the buffer + * Return: 0 on success, or a negative error code + */ +int spl_ram_load(struct spl_image_info *spl_image, void *buf, size_t size); + +/** + * spl_fastboot_load() - Load an image after the fastboot USB session has stopped * @spl_image: Receives the image's load address and entry point * Return: 0 on success, -EAGAIN if no boot was requested, or another error */ diff --git a/include/spl_load.h b/include/spl_load.h index 31ed5651f7b..44c972b10fd 100644 --- a/include/spl_load.h +++ b/include/spl_load.h @@ -114,6 +114,8 @@ static inline int _spl_load(struct spl_image_info *spl_image, IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) + \ IS_ENABLED(CONFIG_SPL_SEMIHOSTING) + \ IS_ENABLED(CONFIG_SPL_SPI_LOAD) + \ + (IS_ENABLED(CONFIG_SPL_FASTBOOT_BOOT) && \ + IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT)) + \ 0 #if SPL_LOAD_USERS > 1 diff --git a/test/image/spl_fastboot.c b/test/image/spl_fastboot.c index 39dc784e5e6..1263416ba8d 100644 --- a/test/image/spl_fastboot.c +++ b/test/image/spl_fastboot.c @@ -92,6 +92,12 @@ static int check_download(struct unit_test_state *uts, void *image, size_t size, ut_assert(ret < 0); return 0; } + if (CONFIG_IS_ENABLED(FIT_SIGNATURE) && + !(expected->flags & SPL_FIT_FOUND)) { + ut_asserteq(-EPERM, ret); + ut_asserteq(0, loaded.size); + return 0; + } ut_assertok(ret); ut_assertok(check_image_info(uts, expected, &loaded)); ut_asserteq_mem(data, map_sysmem(expected->load_addr, expected->size), @@ -106,10 +112,12 @@ static int check_images(struct unit_test_state *uts, void *image, size_t size, struct andr_boot_img_hdr_v0 *hdr = wrapped; size_t wrapped_size = 2048 + size; u32 magic; + bool fit = image_get_magic(image) == FDT_MAGIC; ut_assertok(check_download(uts, image, size, info, data)); - /* Truncated FIT metadata and external payloads must both fail. */ - ut_assertok(check_download(uts, image, sizeof(struct fdt_header) - 1, + /* Both metadata and payload must fit in the completed download. */ + ut_assertok(check_download(uts, image, (fit ? sizeof(struct fdt_header) : + sizeof(struct legacy_img_hdr)) - 1, NULL, NULL)); if (type == FIT_EXTERNAL) ut_assertok(check_download(uts, image, fdt_totalsize(image) - 1, @@ -181,3 +189,4 @@ out: SPL_IMG_TEST(spl_test_fastboot, FIT_INTERNAL, 0); SPL_IMG_TEST(spl_test_fastboot, FIT_EXTERNAL, 0); +SPL_IMG_TEST(spl_test_fastboot, LEGACY, 0); -- 2.56.0
