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) {