From 3a51b22abca25c6a895d2dd40f25bfdc11921a2a Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 18 Dec 2023 11:41:23 +0000 Subject: [PATCH] mgmt: mcumgr: grp: img_mgmt: Add optional max image size reduction Adds an optional feature that can be used to reduce the maximum allowed image upload file size whereby an image could be uploaded that would be too large to swap even if it could fit the partition Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig | 32 ++++++++ .../mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 82 +++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig index 81fc57d92385d32..4a43a748e906613 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig @@ -153,6 +153,38 @@ config MCUMGR_GRP_IMG_MUTEX can be used by applications to reset the image management state (useful if there are multiple ways that firmware updates can be loaded). +choice MCUMGR_GRP_IMG_TOO_LARGE_CHECK + prompt "Image size check overhead" + default MCUMGR_GRP_IMG_TOO_LARGE_DISABLED + help + MCUboot images should be limited to the maximum size that the bootloader can swap, in + order to know this size, additional information is needed from the MCUboot + configuration, otherwise an image can be uploaded that is too large for the bootloader + to swap, this selects which method to use. + + Note: setting this to a non-disabled option will prevent uploading of padded and + confirmed images, if support for that is required then this feature should be left as + disabled. + +config MCUMGR_GRP_IMG_TOO_LARGE_DISABLED + bool "Disabled" + help + Will not take MCUboot configuration into account when checking for maximum file size. + +config MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD + bool "Via Sysbuild from MCUboot configuration" + depends on ROM_END_OFFSET > 0 + help + Will use the image overhead size calculated during Sysbuild image configuration. + +config MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO + bool "Via retention bootloader info" + depends on RETENTION_BOOTLOADER_INFO_OUTPUT_FUNCTION + help + Will fetch the maximum image size from the bootloader info retention subsystem module. + +endchoice + module = MCUMGR_GRP_IMG module-str = mcumgr_grp_img source "subsys/logging/Kconfig.template.log_config" diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c index 303f112709a1e34..9ed3cab36dec39a 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c @@ -19,6 +19,11 @@ #include +#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO) +#include +#include +#endif + LOG_MODULE_DECLARE(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL); #define SLOT0_PARTITION slot0_partition @@ -564,6 +569,18 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, if (req->off == 0) { /* First upload chunk. */ const struct flash_area *fa; +#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \ + (defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \ + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0 + const struct flash_area *fa_current; + int current_img_area; +#elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO) + int max_image_size; +#endif if (req->img_data.len < sizeof(struct image_header)) { /* Image header is the first thing in the image */ @@ -576,6 +593,7 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed); return IMG_MGMT_ERR_INVALID_LENGTH; } + action->size = req->size; hdr = (struct image_header *)req->img_data.value; @@ -626,6 +644,70 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE; } +#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \ + !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP) && \ + !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER) && \ + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0 + +//check if direct XIP (without revert) is needed +#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) + /* Check if slot1 is larger than slot0 by the update size, if so then the size + * check can be skipped because the devicetree partitions are okay + */ + current_img_area = img_mgmt_flash_area_id(req->image); + + rc = flash_area_open(current_img_area, &fa_current); + if (rc) { + IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, + img_mgmt_err_str_flash_open_failed); + LOG_ERR("Failed to open flash area ID %u: %d", current_img_area, rc); + flash_area_close(fa); + return IMG_MGMT_ERR_FLASH_OPEN_FAILED; + } + + flash_area_close(fa_current); + + LOG_DBG("Primary size: %d, secondary size: %d, overhead: %d, max update size: %d", + fa_current->fa_size, fa->fa_size, CONFIG_ROM_END_OFFSET, + (fa->fa_size + CONFIG_ROM_END_OFFSET)); + + if (fa_current->fa_size >= (fa->fa_size + CONFIG_ROM_END_OFFSET)) { + /* Upgrade slot is of sufficient size, nothing to check */ + goto skip_size_check; + } +#endif + + if (req->size > (fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) { + IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, + img_mgmt_err_str_image_too_large); + flash_area_close(fa); + LOG_ERR("Upload too large for slot (with end offset): %u > %u", req->size, + (fa->fa_size - CONFIG_ROM_END_OFFSET)); + return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE; + } + +#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) +skip_size_check: +#endif +#elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO) + rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, (char *)&max_image_size, + sizeof(max_image_size)); + + if (rc == sizeof(max_image_size) && max_image_size > 0 && + req->size > max_image_size) { + IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, + img_mgmt_err_str_image_too_large); + flash_area_close(fa); + LOG_ERR("Upload too large for slot (with max image size): %u > %u", + req->size, max_image_size); + return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE; + } +#endif + #if defined(CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT) if (hdr->ih_flags & IMAGE_F_ROM_FIXED) { if (fa->fa_off != hdr->ih_load_addr) {