diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 4c9df65bf7..82e1abddbb 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -177,12 +177,19 @@ static int boot_serial_get_hash(const struct image_header *hdr, #endif #endif -static zcbor_state_t cbor_state[2]; +#ifdef ZCBOR_CANONICAL +/* Allow 3 extra states for backup states for all commands */ +#define CBOR_EXTRA_STATES 3 +#else +#define CBOR_EXTRA_STATES 0 +#endif + +static zcbor_state_t cbor_state[2 + CBOR_EXTRA_STATES]; void reset_cbor_state(void) { - zcbor_new_encode_state(cbor_state, 2, (uint8_t *)bs_obuf, - sizeof(bs_obuf), 0); + zcbor_new_encode_state(cbor_state, ARRAY_SIZE(cbor_state), (uint8_t *)bs_obuf, + sizeof(bs_obuf), 0); } /** @@ -497,6 +504,7 @@ bs_set(char *buf, int len) * "hash": * } */ + uint32_t slot; uint8_t image_index = 0; size_t decoded = 0; uint8_t hash[IMAGE_HASH_SIZE]; @@ -509,8 +517,8 @@ bs_set(char *buf, int len) bool found = false; #endif - zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); + zcbor_state_t zsd[4 + CBOR_EXTRA_STATES]; + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), (uint8_t *)buf, len, 1, NULL, 0); struct zcbor_map_decode_key_val image_set_state_decode[] = { ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_bool_decode, &confirm), @@ -536,98 +544,106 @@ bs_set(char *buf, int len) } if (img_hash.len != 0) { - for (image_index = 0; image_index < BOOT_IMAGE_NUMBER; ++image_index) { - struct image_header hdr; - uint32_t area_id; - const struct flash_area *fap; - uint8_t tmpbuf[64]; + IMAGES_ITER(image_index) { +#ifdef MCUBOOT_SWAP_USING_OFFSET + int swap_status = boot_swap_type_multi(image_index); +#endif + + for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { + struct image_header hdr; + uint32_t area_id; + const struct flash_area *fap; + uint8_t tmpbuf[64]; #ifdef MCUBOOT_SWAP_USING_OFFSET - uint32_t num_sectors = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN; - struct flash_sector sector_data; - uint32_t start_off = 0; + uint32_t num_sectors = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN; + struct flash_sector sector_data; + uint32_t start_off = 0; #endif - area_id = flash_area_id_from_multi_image_slot(image_index, 1); - if (flash_area_open(area_id, &fap)) { - BOOT_LOG_ERR("Failed to open flash area ID %d", area_id); - continue; - } + area_id = flash_area_id_from_multi_image_slot(image_index, slot); + if (flash_area_open(area_id, &fap)) { + BOOT_LOG_ERR("Failed to open flash area ID %d", area_id); + continue; + } #ifdef MCUBOOT_SWAP_USING_OFFSET - rc = flash_area_sectors(fap, &num_sectors, §or_data); + if (slot == BOOT_SECONDARY_SLOT && swap_status != BOOT_SWAP_TYPE_REVERT) { + rc = flash_area_sectors(fap, &num_sectors, §or_data); - if ((rc != 0 && rc != -ENOMEM) || - num_sectors != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) { - flash_area_close(fap); - continue; - } + if ((rc != 0 && rc != -ENOMEM) || + num_sectors != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) { + flash_area_close(fap); + continue; + } - start_off = sector_data.fs_size; + start_off = sector_data.fs_size; + } #endif - rc = BOOT_HOOK_CALL(boot_read_image_header_hook, - BOOT_HOOK_REGULAR, image_index, 1, &hdr); - if (rc == BOOT_HOOK_REGULAR) - { + rc = BOOT_HOOK_CALL(boot_read_image_header_hook, + BOOT_HOOK_REGULAR, image_index, 1, &hdr); + if (rc == BOOT_HOOK_REGULAR) + { #ifdef MCUBOOT_SWAP_USING_OFFSET - flash_area_read(fap, start_off, &hdr, sizeof(hdr)); + flash_area_read(fap, start_off, &hdr, sizeof(hdr)); #else - flash_area_read(fap, 0, &hdr, sizeof(hdr)); + flash_area_read(fap, 0, &hdr, sizeof(hdr)); #endif - } - - if (hdr.ih_magic == IMAGE_MAGIC) - { - FIH_DECLARE(fih_rc, FIH_FAILURE); + } - BOOT_HOOK_CALL_FIH(boot_image_check_hook, - FIH_BOOT_HOOK_REGULAR, - fih_rc, image_index, 1); - if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) + if (hdr.ih_magic == IMAGE_MAGIC) { + FIH_DECLARE(fih_rc, FIH_FAILURE); + + BOOT_HOOK_CALL_FIH(boot_image_check_hook, + FIH_BOOT_HOOK_REGULAR, + fih_rc, image_index, 1); + if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) + { #ifdef MCUBOOT_ENC_IMAGES - if (IS_ENCRYPTED(&hdr)) { + if (IS_ENCRYPTED(&hdr)) { #ifdef MCUBOOT_SWAP_USING_OFFSET - FIH_CALL(boot_image_validate_encrypted, fih_rc, fap, - &hdr, tmpbuf, sizeof(tmpbuf), start_off); + FIH_CALL(boot_image_validate_encrypted, fih_rc, fap, + &hdr, tmpbuf, sizeof(tmpbuf), start_off); #else - FIH_CALL(boot_image_validate_encrypted, fih_rc, fap, - &hdr, tmpbuf, sizeof(tmpbuf)); + FIH_CALL(boot_image_validate_encrypted, fih_rc, fap, + &hdr, tmpbuf, sizeof(tmpbuf)); #endif - } else { + } else { #endif #ifdef MCUBOOT_SWAP_USING_OFFSET - FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr, - fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL, start_off); + FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr, + fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL, start_off); #else - FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr, - fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL); + FIH_CALL(bootutil_img_validate, fih_rc, NULL, &hdr, + fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL); #endif #ifdef MCUBOOT_ENC_IMAGES - } + } #endif - } + } - if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { - continue; + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + continue; + } } - } #ifdef MCUBOOT_SERIAL_IMG_GRP_HASH - /* Retrieve hash of image for identification */ + /* Retrieve hash of image for identification */ #ifdef MCUBOOT_SWAP_USING_OFFSET - rc = boot_serial_get_hash(&hdr, fap, hash, start_off); + rc = boot_serial_get_hash(&hdr, fap, hash, start_off); #else - rc = boot_serial_get_hash(&hdr, fap, hash); + rc = boot_serial_get_hash(&hdr, fap, hash); #endif #endif - flash_area_close(fap); + flash_area_close(fap); - if (rc == 0 && memcmp(hash, img_hash.value, sizeof(hash)) == 0) { - /* Hash matches, set this slot for test or confirmation */ - found = true; - break; + if (rc == 0 && memcmp(hash, img_hash.value, sizeof(hash)) == 0) { + /* Hash matches, set this slot for test or confirmation */ + found = true; + goto set_image_state; + } } } @@ -640,6 +656,7 @@ bs_set(char *buf, int len) } #endif +set_image_state: rc = boot_set_pending_multi(image_index, confirm); out: @@ -683,6 +700,8 @@ bs_list_set(uint8_t op, char *buf, int len) bs_rc_rsp(MGMT_ERR_ENOTSUP); #endif } + + reset_cbor_state(); } #ifdef MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO @@ -856,7 +875,7 @@ static off_t erase_range(const struct flash_area *fap, off_t start, off_t end) BOOT_LOG_DBG("Erasing range 0x%jx:0x%jx", (intmax_t)start, (intmax_t)(start + size - 1)); - rc = boot_erase_region(fap, start, size); + rc = boot_erase_region(fap, start, size, false); if (rc != 0) { BOOT_LOG_ERR("Error %d while erasing range", rc); return -EINVAL; @@ -901,8 +920,8 @@ bs_upload(char *buf, int len) static uint32_t start_off = 0; #endif - zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); + zcbor_state_t zsd[4 + CBOR_EXTRA_STATES]; + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), (uint8_t *)buf, len, 1, NULL, 0); struct zcbor_map_decode_key_val image_upload_decode[] = { ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num_tmp), @@ -1000,7 +1019,7 @@ bs_upload(char *buf, int len) /* Non-progressive erase erases entire image slot when first chunk of * an image is received. */ - rc = boot_erase_region(fap, 0, area_size); + rc = boot_erase_region(fap, 0, area_size, false); if (rc) { goto out_invalid_data; } @@ -1210,8 +1229,8 @@ bs_echo(char *buf, int len) bool ok; uint32_t rc = MGMT_ERR_EINVAL; - zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); + zcbor_state_t zsd[4 + CBOR_EXTRA_STATES]; + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), (uint8_t *)buf, len, 1, NULL, 0); if (!zcbor_map_start_decode(zsd)) { goto out; diff --git a/boot/boot_serial/src/boot_serial_encryption.c b/boot/boot_serial/src/boot_serial_encryption.c index 81af6b8501..60ad587cb0 100644 --- a/boot/boot_serial/src/boot_serial_encryption.c +++ b/boot/boot_serial/src/boot_serial_encryption.c @@ -11,7 +11,6 @@ #include "bootutil/bootutil_log.h" #include "bootutil/bootutil_public.h" #include "bootutil/fault_injection_hardening.h" -#include "bootutil/enc_key.h" #include "mcuboot_config/mcuboot_config.h" @@ -187,7 +186,7 @@ decrypt_region_inplace(struct boot_loader_state *state, (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, blk_off, &buf[idx]); } - rc = boot_erase_region(fap, off + bytes_copied, chunk_sz); + rc = boot_erase_region(fap, off + bytes_copied, chunk_sz, false); if (rc != 0) { return BOOT_EFLASH; } diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h index 23862825cd..e5416dca02 100644 --- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h @@ -19,30 +19,27 @@ #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT or PSA" #endif +#include "bootutil/enc_key_public.h" + #if defined(MCUBOOT_USE_MBED_TLS) #include - #include "bootutil/enc_key_public.h" - #define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE - #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16) + #define BOOT_ENC_BLOCK_SIZE (16) #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) - #if defined(MCUBOOT_AES_256) - #error "Cannot use AES-256 for encryption with Tinycrypt library." - #endif #include #include #include #include - #define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE TC_AES_KEY_SIZE - #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE TC_AES_BLOCK_SIZE + #if defined(MCUBOOT_AES_256) || (BOOT_ENC_KEY_SIZE != TC_AES_KEY_SIZE) + #error "Cannot use AES-256 for encryption with Tinycrypt library." + #endif + #define BOOT_ENC_BLOCK_SIZE TC_AES_BLOCK_SIZE #endif /* MCUBOOT_USE_TINYCRYPT */ #if defined(MCUBOOT_USE_PSA_CRYPTO) #include - #include "bootutil/enc_key_public.h" - #define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE - #define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16) + #define BOOT_ENC_BLOCK_SIZE (16) #endif #include @@ -91,18 +88,18 @@ static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) { - return mbedtls_aes_setkey_enc(ctx, k, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE * 8); + return mbedtls_aes_setkey_enc(ctx, k, BOOT_ENC_KEY_SIZE * 8); } static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c) { - uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE]; + uint8_t stream_block[BOOT_ENC_BLOCK_SIZE]; return mbedtls_aes_crypt_ctr(ctx, mlen, &blk_off, counter, stream_block, m, c); } static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m) { - uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE]; + uint8_t stream_block[BOOT_ENC_BLOCK_SIZE]; return mbedtls_aes_crypt_ctr(ctx, clen, &blk_off, counter, stream_block, c, m); } #endif /* MCUBOOT_USE_MBED_TLS */ diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index f125623295..e53715b657 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -4,6 +4,7 @@ * Copyright (c) 2017-2019 Linaro LTD * Copyright (c) 2016-2019 JUUL Labs * Copyright (c) 2019-2020 Arm Limited + * Copyright (c) 2025 Nordic Semiconductor ASA * * Original license: * @@ -557,3 +558,108 @@ boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) return rc; } #endif /* !MCUBOOT_OVERWRITE_ONLY */ + +/** + * Erases a region of device that requires erase prior to write; does + * nothing on devices without erase. + * + * @param fa The flash_area containing the region to erase. + * @param off The offset within the flash area to start the + * erase. + * @param size The number of bytes to erase. + * @param backwards If set to true will erase from end to start + * addresses, otherwise erases from start to end + * addresses. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool backwards) +{ + int rc = 0; + + if (off >= flash_area_get_size(fa) || (flash_area_get_size(fa) - off) < size) { + rc = -1; + goto end; + } else if (device_requires_erase(fa)) { + uint32_t end_offset = 0; + struct flash_sector sector; + + if (backwards) { + /* Get the lowest page offset first */ + rc = flash_area_get_sector(fa, off, §or); + + if (rc < 0) { + goto end; + } + + end_offset = flash_sector_get_off(§or); + + /* Set boundary condition, the highest probable offset to erase, within + * last sector to erase + */ + off += size - 1; + } else { + /* Get the highest page offset first */ + rc = flash_area_get_sector(fa, (off + size - 1), §or); + + if (rc < 0) { + goto end; + } + + end_offset = flash_sector_get_off(§or); + } + + while (true) { + /* Size to read in this iteration */ + size_t csize; + + /* Get current sector and, also, correct offset */ + rc = flash_area_get_sector(fa, off, §or); + + if (rc < 0) { + goto end; + } + + /* Corrected offset and size of current sector to erase */ + off = flash_sector_get_off(§or); + csize = flash_sector_get_size(§or); + + rc = flash_area_erase(fa, off, csize); + + if (rc < 0) { + goto end; + } + + MCUBOOT_WATCHDOG_FEED(); + + if (backwards) { + if (end_offset >= off) { + /* Reached the first offset in range and already erased it */ + break; + } + + /* Move down to previous sector, the flash_area_get_sector will + * correct the value to real page offset + */ + off -= 1; + } else { + /* Move up to next sector */ + off += csize; + + if (off > end_offset) { + /* Reached the end offset in range and already erased it */ + break; + } + + /* Workaround for flash_sector_get_off() being broken in mynewt, hangs with + * infinite loop if this is not present, should be removed if bug is fixed. + */ + off += 1; + } + } + } + +end: + return rc; +} diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 95f8f1732e..72e94aee9f 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -346,11 +346,9 @@ int boot_copy_region(struct boot_loader_state *state, /* Prepare for write device that requires erase prior to write. This will * do nothing on devices without erase requirement. */ -int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz); +int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz, bool backwards); /* Similar to boot_erase_region but will always remove data */ -int boot_scramble_region(const struct flash_area *fap, uint32_t off, uint32_t sz); -/* Similar to boot_scramble_region but works backwards */ -int boot_scramble_region_backwards(const struct flash_area *fap, uint32_t off, uint32_t sz); +int boot_scramble_region(const struct flash_area *fap, uint32_t off, uint32_t sz, bool backwards); /* Makes slot unbootable, either by scrambling header magic, header sector * or entire slot, depending on settings. * Note: slot is passed here becuase at this point there is no function diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 6b9e50a645..bbe40751fc 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -422,11 +422,11 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) bootutil_aes_ctr_context aes_ctr; uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; uint8_t shared[SHARED_KEY_LEN]; - uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; + uint8_t derived_key[BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; uint8_t *cp; uint8_t *cpend; uint8_t private_key[PRIV_KEY_LEN]; - uint8_t counter[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE]; + uint8_t counter[BOOT_ENC_BLOCK_SIZE]; uint16_t len; #endif struct bootutil_key *bootutil_enc_key = NULL; @@ -530,10 +530,10 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) * Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256 */ - len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; + len = BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16, derived_key, &len); - if (rc != 0 || len != (BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) { + if (rc != 0 || len != (BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) { return -1; } @@ -585,8 +585,8 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return -1; } - memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE); - rc = bootutil_aes_ctr_decrypt(&aes_ctr, counter, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey); + memset(counter, 0, BOOT_ENC_BLOCK_SIZE); + rc = bootutil_aes_ctr_decrypt(&aes_ctr, counter, &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE, 0, enckey); if (rc != 0) { bootutil_aes_ctr_drop(&aes_ctr); return -1; diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c index 441ce94df9..f30bd62472 100644 --- a/boot/bootutil/src/encrypted_psa.c +++ b/boot/bootutil/src/encrypted_psa.c @@ -28,10 +28,12 @@ BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc); #define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE -#define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 #define EC_PUBK_INDEX (0) -#define EC_TAG_INDEX (32) -#define EC_CIPHERKEY_INDEX (32 + 32) +#define EC_PUBK_LEN (32) +#define EC_TAG_INDEX (EC_PUBK_INDEX + EC_PUBK_LEN) +#define EC_TAG_LEN (32) +#define EC_CIPHERKEY_INDEX (EC_TAG_INDEX + EC_TAG_LEN) +#define EC_CIPHERKEY_LEN BOOT_ENC_KEY_SIZE _Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, "Please fix ECIES-X25519 component indexes"); @@ -39,7 +41,6 @@ _Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ MBEDTLS_OID_ORG_GOV X25519_OID; -#define SHARED_KEY_LEN 32 #define PRIV_KEY_LEN 32 /* Fixme: This duplicates code from encrypted.c and depends on mbedtls */ @@ -113,7 +114,7 @@ extern const struct bootutil_key bootutil_enc_key; int boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) { - uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; + uint8_t derived_key[BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; uint8_t *cp; uint8_t *cpend; uint8_t private_key[PRIV_KEY_LEN]; @@ -133,7 +134,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) * the beginning of the input buffer. */ uint8_t iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR) + - BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE]; + BOOT_ENC_KEY_SIZE]; psa_ret = psa_crypto_init(); if (psa_ret != PSA_SUCCESS) { @@ -180,7 +181,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) */ psa_ret = psa_key_derivation_key_agreement(&key_do, PSA_KEY_DERIVATION_INPUT_SECRET, kid, &buf[EC_PUBK_INDEX], - BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); + EC_PUBK_LEN); psa_cleanup_ret = psa_destroy_key(kid); if (psa_cleanup_ret != PSA_SUCCESS) { BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret); @@ -207,7 +208,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return -1; } - len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; + len = BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; psa_ret = psa_key_derivation_output_bytes(&key_do, derived_key, len); psa_cleanup_ret = psa_key_derivation_abort(&key_do); if (psa_cleanup_ret != PSA_SUCCESS) { @@ -218,7 +219,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return -1; } - /* The derived key consists of BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE bytes + /* The derived key consists of BOOT_ENC_KEY_SIZE bytes * followed by BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. Both parts will * be imported at the point where needed and discarded immediately after. */ @@ -227,11 +228,11 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) psa_set_key_algorithm(&kattr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); /* Import the MAC tag key part of derived key, that is the part that starts - * after BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE and has length of + * after BOOT_ENC_KEY_SIZE and has length of * BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. */ psa_ret = psa_import_key(&kattr, - &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE], + &derived_key[BOOT_ENC_KEY_SIZE], BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, &kid); psa_reset_key_attributes(&kattr); if (psa_ret != PSA_SUCCESS) { @@ -242,9 +243,9 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) /* Verify the MAC tag of the random encryption key */ psa_ret = psa_mac_verify(kid, PSA_ALG_HMAC(PSA_ALG_SHA_256), - &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE, + &buf[EC_CIPHERKEY_INDEX], EC_CIPHERKEY_LEN, &buf[EC_TAG_INDEX], - BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); + EC_TAG_LEN); psa_cleanup_ret = psa_destroy_key(kid); if (psa_cleanup_ret != PSA_SUCCESS) { BOOT_LOG_WRN("MAC key destruction failed %d", psa_cleanup_ret); @@ -261,8 +262,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) psa_set_key_algorithm(&kattr, PSA_ALG_CTR); /* Import the AES partition of derived key, the first 16 bytes */ - psa_ret = psa_import_key(&kattr, &derived_key[0], - BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &kid); + psa_ret = psa_import_key(&kattr, &derived_key[0], BOOT_ENC_KEY_SIZE, &kid); memset(derived_key, 0, sizeof(derived_key)); if (psa_ret != PSA_SUCCESS) { BOOT_LOG_ERR("AES key import failed %d", psa_ret); @@ -278,14 +278,14 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) len = 0; psa_ret = psa_cipher_decrypt(kid, PSA_ALG_CTR, iv_and_key, sizeof(iv_and_key), - enckey, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &len); + enckey, BOOT_ENC_KEY_SIZE, &len); memset(iv_and_key, 0, sizeof(iv_and_key)); psa_cleanup_ret = psa_destroy_key(kid); if (psa_cleanup_ret != PSA_SUCCESS) { BOOT_LOG_WRN("AES key destruction failed %d", psa_cleanup_ret); } - if (psa_ret != PSA_SUCCESS || len != BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE) { - memset(enckey, 0, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE); + if (psa_ret != PSA_SUCCESS || len != BOOT_ENC_KEY_SIZE) { + memset(enckey, 0, BOOT_ENC_KEY_SIZE); BOOT_LOG_ERR("Random key decryption failed %d", psa_ret); return -1; } diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 9c98da30cb..f47ec4e2a0 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1229,26 +1229,6 @@ boot_validated_swap_type(struct boot_loader_state *state, } #endif -/** - * Erases a region of device that requires erase prior to write; does - * nothing on devices without erase. - * - * @param fap The flash_area containing the region to erase. - * @param off The offset within the flash area to start the - * erase. - * @param sz The number of bytes to erase. - * - * @return 0 on success; nonzero on failure. - */ -int -boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz) -{ - if (device_requires_erase(fap)) { - return flash_area_erase(fap, off, sz); - } - return 0; -} - /** * Removes data from specified region either by writing erase value in place of * data or by doing erase, if device has such hardware requirement. @@ -1259,36 +1239,70 @@ boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz) * @param off The offset within the flash area to start the * erase. * @param size The number of bytes to erase. + * @param backwards If set to true will erase from end to start + * addresses, otherwise erases from start to end + * addresses. * * @return 0 on success; nonzero on failure. */ int -boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size) +boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool backwards) { - int ret = 0; + int rc = 0; if (size == 0) { - return 0; + goto done; } if (device_requires_erase(fa)) { - return flash_area_erase(fa, off, size); + rc = boot_erase_region(fa, off, size, backwards); + } else if (off >= flash_area_get_size(fa) || (flash_area_get_size(fa) - off) < size) { + rc = -1; + goto done; } else { uint8_t buf[BOOT_MAX_ALIGN]; - size_t size_done = 0; const size_t write_block = flash_area_align(fa); + uint32_t end_offset; memset(buf, flash_area_erased_val(fa), sizeof(buf)); - while (size_done < size) { - ret = flash_area_write(fa, size_done + off, buf, write_block); - if (ret != 0) { + if (backwards) { + end_offset = ALIGN_DOWN(off, write_block); + /* Starting at the last write block in range */ + off += size - write_block; + } else { + end_offset = ALIGN_DOWN((off + size), write_block); + } + + while (true) { + /* Write over the area to scramble data that is there */ + rc = flash_area_write(fa, off, buf, write_block); + if (rc != 0) { break; } - size_done += write_block; + + MCUBOOT_WATCHDOG_FEED(); + + if (backwards) { + if (end_offset >= off) { + /* Reached the first offset in range and already scrambled it */ + break; + } + + off -= write_block; + } else { + if (end_offset < off) { + /* Reached the end offset in range and already scrambled it */ + break; + } + + off += write_block; + } } } - return ret; + +done: + return rc; } /** @@ -1304,90 +1318,6 @@ boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size) * * @return 0 on success; nonzero on failure. */ -int boot_scramble_region_backwards(const struct flash_area *fa, uint32_t off, uint32_t size) -{ - int ret = 0; - uint32_t first_offset = 0; - - if (size == 0) { - return 0; - } - - if (off >= flash_area_get_size(fa) || (flash_area_get_size(fa) - off) < size) { - return -1; - } - - if (device_requires_erase(fa)) { - struct flash_sector sector; - - /* Get the lowest erased page offset first */ - ret = flash_area_get_sector(fa, off, §or); - if (ret < 0) { - return ret; - } - first_offset = flash_sector_get_off(§or); - - /* Set boundary condition, the highest probable offset to erase, within - * last sector to erase - */ - off += size - 1; - - while (true) { - /* Size to read in this iteration */ - size_t csize; - - /* Get current sector and, also, correct offset */ - ret = flash_area_get_sector(fa, off, §or); - if (ret < 0) { - return ret; - } - - /* Corrected offset and size of current sector to erase */ - off = flash_sector_get_off(§or); - csize = flash_sector_get_size(§or); - - ret = flash_area_erase(fa, off, csize); - if (ret < 0) { - return ret; - } - - if (first_offset >= off) { - /* Reached the first offsset in range and already erased it */ - break; - } - - /* Move down to previous sector, the flash_area_get_sector will - * correct the value to real page offset - */ - off -= 1; - } - } else { - uint8_t buf[BOOT_MAX_ALIGN]; - const size_t write_block = flash_area_align(fa); - uint32_t first_offset = ALIGN_DOWN(off, write_block); - - memset(buf, flash_area_erased_val(fa), sizeof(buf)); - - /* Starting at the last write block in range */ - off += size - write_block; - - while (true) { - /* Write over the area to scramble data that is there */ - ret = flash_area_write(fa, off, buf, write_block); - if (ret != 0) { - break; - } - - if (first_offset >= off) { - /* Reached the first offset in range and already scrambled it */ - break; - } - - off -= write_block; - } - } - return ret; -} /** * Remove enough data from slot to mark is as unused @@ -1412,7 +1342,7 @@ boot_scramble_slot(const struct flash_area *fa, int slot) /* Without minimal entire area needs to be scrambled */ #if !defined(MCUBOOT_MINIMAL_SCRAMBLE) size = flash_area_get_size(fa); - ret = boot_scramble_region(fa, 0, size); + ret = boot_scramble_region(fa, 0, size, false); #else size_t off = 0; @@ -1421,7 +1351,7 @@ boot_scramble_slot(const struct flash_area *fa, int slot) return ret; } - ret = boot_scramble_region(fa, off, size); + ret = boot_scramble_region(fa, off, size, false); if (ret < 0) { return ret; } @@ -1431,7 +1361,7 @@ boot_scramble_slot(const struct flash_area *fa, int slot) return ret; } - ret = boot_scramble_region_backwards(fa, off, flash_area_get_size(fa) - off); + ret = boot_scramble_region(fa, off, (flash_area_get_size(fa) - off), true); #endif return ret; } @@ -1663,7 +1593,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT); for (sect = 0, size = 0; sect < sect_count; sect++) { this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect); - rc = boot_erase_region(fap_primary_slot, size, this_size); + rc = boot_erase_region(fap_primary_slot, size, this_size, false); assert(rc == 0); #if defined(MCUBOOT_OVERWRITE_ONLY_FAST) @@ -1687,7 +1617,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) sector--; } while (sz < trailer_sz); - rc = boot_erase_region(fap_primary_slot, off, sz); + rc = boot_erase_region(fap_primary_slot, off, sz, false); assert(rc == 0); #endif @@ -1759,7 +1689,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) BOOT_LOG_DBG("erasing secondary header"); rc = boot_erase_region(fap_secondary_slot, boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0), - boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0)); + boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0), false); assert(rc == 0); #endif @@ -1769,7 +1699,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) boot_img_sector_off(state, BOOT_SECONDARY_SLOT, last_sector), boot_img_sector_size(state, BOOT_SECONDARY_SLOT, - last_sector)); + last_sector), false); assert(rc == 0); /* TODO: Perhaps verify the primary slot's signature again? */ @@ -2937,9 +2867,8 @@ boot_select_or_erase(struct boot_loader_state *state) */ BOOT_LOG_DBG("Erasing faulty image in the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary"); - rc = flash_area_erase(fap, 0, flash_area_get_size(fap)); + rc = boot_scramble_region(fap, 0, flash_area_get_size(fap), false); assert(rc == 0); - rc = -1; } else { if (active_swap_state->copy_done != BOOT_FLAG_SET) { diff --git a/boot/bootutil/src/swap_misc.c b/boot/bootutil/src/swap_misc.c index 1244e475e1..ac9412b0fd 100644 --- a/boot/bootutil/src/swap_misc.c +++ b/boot/bootutil/src/swap_misc.c @@ -61,7 +61,7 @@ swap_erase_trailer_sectors(const struct boot_loader_state *state, uint32_t sz = boot_img_sector_size(state, slot, sector); uint32_t off = boot_img_sector_off(state, slot, sector); - rc = boot_erase_region(fap, off, sz); + rc = boot_erase_region(fap, off, sz, false); assert(rc == 0); sector--; @@ -87,7 +87,7 @@ swap_scramble_trailer_sectors(const struct boot_loader_state *state, if (rc < 0) { return BOOT_EFLASH; } - rc = boot_scramble_region_backwards(fap, off, flash_area_get_size(fap) - off); + rc = boot_scramble_region(fap, off, (flash_area_get_size(fap) - off), true); if (rc < 0) { return BOOT_EFLASH; } diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index fd91ad4883..9349cde37f 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -413,7 +413,7 @@ boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state, assert(rc == 0); } - rc = boot_erase_region(fap_pri, new_off, sz); + rc = boot_erase_region(fap_pri, new_off, sz, false); assert(rc == 0); rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz); @@ -440,7 +440,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, sec_off = boot_img_sector_off(state, BOOT_SECONDARY_SLOT, idx - 1); if (bs->state == BOOT_STATUS_STATE_0) { - rc = boot_erase_region(fap_pri, pri_off, sz); + rc = boot_erase_region(fap_pri, pri_off, sz, false); assert(rc == 0); rc = boot_copy_region(state, fap_sec, fap_pri, sec_off, pri_off, sz); @@ -452,7 +452,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, } if (bs->state == BOOT_STATUS_STATE_1) { - rc = boot_erase_region(fap_sec, sec_off, sz); + rc = boot_erase_region(fap_sec, sec_off, sz, false); assert(rc == 0); rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz); diff --git a/boot/bootutil/src/swap_offset.c b/boot/bootutil/src/swap_offset.c index 6caedb3777..8bc6e760a6 100644 --- a/boot/bootutil/src/swap_offset.c +++ b/boot/bootutil/src/swap_offset.c @@ -470,7 +470,7 @@ static void boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *st } else { /* Copy from slot 0 X to slot 1 X */ BOOT_LOG_DBG("Erasing secondary 0x%x of 0x%x", sec_off, sz); - rc = boot_erase_region(fap_sec, sec_off, sz); + rc = boot_erase_region(fap_sec, sec_off, sz, false); assert(rc == 0); BOOT_LOG_DBG("Copying primary 0x%x -> secondary 0x%x of 0x%x", pri_off, sec_off, sz); @@ -490,7 +490,7 @@ static void boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *st } else { /* Erase slot 0 X */ BOOT_LOG_DBG("Erasing primary 0x%x of 0x%x", pri_off, sz); - rc = boot_erase_region(fap_pri, pri_off, sz); + rc = boot_erase_region(fap_pri, pri_off, sz, false); assert(rc == 0); /* Copy from slot 1 (X + 1) to slot 0 X */ @@ -531,7 +531,7 @@ static void boot_swap_sectors_revert(int idx, uint32_t sz, struct boot_loader_st } else { /* Copy from slot 0 X to slot 1 X */ BOOT_LOG_DBG("Erasing secondary 0x%x of 0x%x", sec_off, sz); - rc = boot_erase_region(fap_sec, sec_off, sz); + rc = boot_erase_region(fap_sec, sec_off, sz, false); assert(rc == 0); BOOT_LOG_DBG("Copying primary 0x%x -> secondary 0x%x of 0x%x", pri_off, sec_off, sz); @@ -551,7 +551,7 @@ static void boot_swap_sectors_revert(int idx, uint32_t sz, struct boot_loader_st } else { /* Erase slot 0 X */ BOOT_LOG_DBG("Erasing primary 0x%x of 0x%x", pri_off, sz); - rc = boot_erase_region(fap_pri, pri_off, sz); + rc = boot_erase_region(fap_pri, pri_off, sz, false); assert(rc == 0); /* Copy from slot 1 (X + 1) to slot 0 X */ @@ -710,7 +710,7 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs, * to allow for a future update to be loaded */ rc = boot_scramble_region(fap_sec, boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0), - sector_sz); + sector_sz, false); assert(rc == 0); rc = swap_scramble_trailer_sectors(state, fap_sec); assert(rc == 0); @@ -752,6 +752,9 @@ int boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *si fap = BOOT_IMG_AREA(state, slot); assert(fap != NULL); + assert(size != NULL); + + *size = 0; off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index af4be88a68..f9dbb71033 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -617,7 +617,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, if (bs->state == BOOT_STATUS_STATE_0) { BOOT_LOG_DBG("erasing scratch area"); - rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch)); + rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch), false); assert(rc == 0); if (bs->idx == BOOT_STATUS_IDX_0) { @@ -641,7 +641,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, /* Erase the temporary trailer from the scratch area. */ rc = boot_erase_region(fap_scratch, 0, - flash_area_get_size(fap_scratch)); + flash_area_get_size(fap_scratch), false); assert(rc == 0); } } @@ -683,7 +683,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, } if (erase_sz > 0) { - rc = boot_erase_region(fap_secondary_slot, img_off, erase_sz); + rc = boot_erase_region(fap_secondary_slot, img_off, erase_sz, false); assert(rc == 0); } @@ -716,7 +716,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, } if (erase_sz > 0) { - rc = boot_erase_region(fap_primary_slot, img_off, erase_sz); + rc = boot_erase_region(fap_primary_slot, img_off, erase_sz, false); assert(rc == 0); } @@ -778,7 +778,12 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, BOOT_STATUS_ASSERT(rc == 0); if (erase_scratch) { - rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch)); + /* Scratch trailers MUST be erased backwards, this is to avoid an issue whereby a + * device reboots in the process of erasing the scratch if it erased forwards, if that + * happens then the scratch which is partially erased would be wrote back to the + * primary slot, causing a corrupt unbootable image + */ + rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch), true); assert(rc == 0); } } diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index be66515576..acc0314a66 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -213,6 +213,10 @@ config BOOT_SIGNATURE_TYPE_RSA select BOOT_USE_MBEDTLS select MBEDTLS select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN + select MBEDTLS_MD if MBEDTLS_BUILTIN + select MBEDTLS_RSA_C if MBEDTLS_BUILTIN + select MBEDTLS_PKCS1_V15 if MBEDTLS_BUILTIN + select MBEDTLS_PKCS1_V21 if MBEDTLS_BUILTIN select MBEDTLS_KEY_EXCHANGE_RSA_ENABLED if MBEDTLS_BUILTIN select BOOT_ENCRYPTION_SUPPORT select BOOT_IMG_HASH_ALG_SHA256_ALLOW @@ -446,7 +450,7 @@ config BOOT_SWAP_USING_OFFSET the second sector in the second slot instead of the first. config BOOT_SWAP_USING_MOVE - bool "Swap using mode mode without scratch partition" + bool "Swap using move mode without scratch partition" help If y, the swap upgrade is done in two steps, where first every sector of the primary slot is moved up one sector, then for @@ -755,6 +759,32 @@ config BOOT_FIH_PROFILE_HIGH endchoice +config BOOT_USE_BENCH + bool "Enable benchmark code" + help + If y, adds support for simple benchmarking that can record + time intervals between two calls. The time printed depends + on the particular Zephyr target, and is generally ticks of a + specific board-specific timer. + +module = MCUBOOT +module-str = MCUBoot bootloader +source "subsys/logging/Kconfig.template.log_config" + +config MCUBOOT_LOG_THREAD_STACK_SIZE + int "Stack size for the MCUBoot log processing thread" + depends on LOG && !LOG_IMMEDIATE + default 2048 if COVERAGE_GCOV + default 1024 if NO_OPTIMIZATIONS + default 1024 if XTENSA + default 4096 if (X86 && X86_64) + default 4096 if ARM64 + default 768 + help + Set the internal stack size for MCUBoot log processing thread. + +menu "USB DFU" + choice BOOT_USB_DFU prompt "USB DFU" default BOOT_USB_DFU_NO @@ -807,44 +837,24 @@ endif # BOOT_USB_DFU_GPIO config BOOT_USB_DFU_NO_APPLICATION bool "Stay in bootloader if no application" + depends on !BOOT_USB_DFU_NO help Allows for entering USB DFU recovery mode if there is no bootable application that the bootloader can jump to. -config BOOT_USE_BENCH - bool "Enable benchmark code" - help - If y, adds support for simple benchmarking that can record - time intervals between two calls. The time printed depends - on the particular Zephyr target, and is generally ticks of a - specific board-specific timer. - -module = MCUBOOT -module-str = MCUBoot bootloader -source "subsys/logging/Kconfig.template.log_config" +endmenu -config MCUBOOT_LOG_THREAD_STACK_SIZE - int "Stack size for the MCUBoot log processing thread" - depends on LOG && !LOG_IMMEDIATE - default 2048 if COVERAGE_GCOV - default 1024 if NO_OPTIMIZATIONS - default 1024 if XTENSA - default 4096 if (X86 && X86_64) - default 4096 if ARM64 - default 768 - help - Set the internal stack size for MCUBoot log processing thread. +rsource "Kconfig.serial_recovery" config MCUBOOT_INDICATION_LED bool "Turns on LED indication when device is in DFU" select GPIO + depends on MCUBOOT_SERIAL || !BOOT_USB_DFU_NO help Device device activates the LED while in bootloader mode. mcuboot-led0 alias must be set in the device's .dts definitions for this to work. -rsource "Kconfig.serial_recovery" - rsource "Kconfig.firmware_loader" config BOOT_INTR_VEC_RELOC @@ -1012,24 +1022,6 @@ endif # BOOT_DECOMPRESSION endif # BOOT_DECOMPRESSION_SUPPORT -menu "Defaults" - # Items in this menu should not be manually set. These options are for modules/sysbuild to - # set as defaults to allow MCUboot's default configuration to be set, but still allow it - # to be overridden by users. - -config BOOT_FIH_PROFILE_DEFAULT_LOW - bool "Default to low fault inject hardening level" - -config BOOT_FIH_PROFILE_DEFAULT_MEDIUM - bool "Default to medium fault inject hardening level" - -config BOOT_FIH_PROFILE_DEFAULT_HIGH - bool "Default to high fault inject hardening level" - -endmenu - -endmenu - config MCUBOOT_STORAGE_WITHOUT_ERASE bool "Support for devices without erase" depends on FLASH_HAS_NO_EXPLICIT_ERASE @@ -1053,7 +1045,8 @@ config MCUBOOT_STORAGE_WITH_ERASE Support for devices with erase config MCUBOOT_STORAGE_MINIMAL_SCRAMBLE - bool "Do minimal required work to remove data (EXPERIMENTAL)" + bool "Do minimal required work to remove data [EXPERIMENTAL]" + select EXPERIMENTAL help In some cases MCUboot has to remove data, which usually means make it non-viable for MCUboot rather then completely destroyed. @@ -1068,6 +1061,22 @@ config MCUBOOT_STORAGE_MINIMAL_SCRAMBLE Depending on type of device this may be done by erase of minimal number of pages or overwrite of part of image. +menu "Defaults" + # Items in this menu should not be manually set. These options are for modules/sysbuild to + # set as defaults to allow MCUboot's default configuration to be set, but still allow it + # to be overridden by users. + +config BOOT_FIH_PROFILE_DEFAULT_LOW + bool "Default to low fault inject hardening level" + +config BOOT_FIH_PROFILE_DEFAULT_MEDIUM + bool "Default to medium fault inject hardening level" + +config BOOT_FIH_PROFILE_DEFAULT_HIGH + bool "Default to high fault inject hardening level" + +endmenu + config MCUBOOT_DEVICE_SETTINGS # Hidden selector for device-specific settings bool @@ -1084,6 +1093,8 @@ config MCUBOOT_DEVICE_CPU_CORTEX_M0 bool select SW_VECTOR_RELAY if !CPU_CORTEX_M0_HAS_VECTOR_TABLE_REMAP +endmenu + comment "Zephyr configuration options" # Disabling MULTITHREADING provides a code size advantage, but diff --git a/boot/zephyr/include/flash_map_backend/flash_map_backend.h b/boot/zephyr/include/flash_map_backend/flash_map_backend.h index 81a1832598..ed73811cdc 100644 --- a/boot/zephyr/include/flash_map_backend/flash_map_backend.h +++ b/boot/zephyr/include/flash_map_backend/flash_map_backend.h @@ -9,6 +9,7 @@ #define __FLASH_MAP_BACKEND_H__ #include // the zephyr flash_map +#include #ifdef __cplusplus extern "C" { @@ -111,13 +112,15 @@ int flash_area_get_sector(const struct flash_area *fa, off_t off, static inline bool flash_area_erase_required(const struct flash_area *fa) { #if defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE) && defined(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE) - const struct flash_parameters *fp = flash_get_parameters(flash_area_get_device(fa)); - return flash_params_get_erase_cap(flash_get_parameters(flash_area_get_device(fa))) & FLASH_ERASE_C_EXPLICIT; #elif defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE) + (void)fa; + return true; #else + (void)fa; + return false; #endif } diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 119e075792..02b27f1c44 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -32,5 +32,7 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_MCUBOOT_LOG_LEVEL_INF=y ### Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y CONFIG_CBPRINTF_NANO=y -### Use the minimal C library to reduce flash usage -CONFIG_MINIMAL_LIBC=y +### Use picolibc to reduce flash usage +CONFIG_PICOLIBC=y +### Disable malloc arena because we don't need it +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32_procpu.conf b/boot/zephyr/socs/esp32_procpu.conf index b2b405922a..7d3368bad0 100644 --- a/boot/zephyr/socs/esp32_procpu.conf +++ b/boot/zephyr/socs/esp32_procpu.conf @@ -16,4 +16,5 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32c2.conf b/boot/zephyr/socs/esp32c2.conf index 5b49f163bb..8fdaa88528 100644 --- a/boot/zephyr/socs/esp32c2.conf +++ b/boot/zephyr/socs/esp32c2.conf @@ -17,4 +17,5 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32c3.conf b/boot/zephyr/socs/esp32c3.conf index 56298cd4ff..96b81e7973 100644 --- a/boot/zephyr/socs/esp32c3.conf +++ b/boot/zephyr/socs/esp32c3.conf @@ -17,4 +17,5 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32c6.conf b/boot/zephyr/socs/esp32c6.conf index 5b49f163bb..8fdaa88528 100644 --- a/boot/zephyr/socs/esp32c6.conf +++ b/boot/zephyr/socs/esp32c6.conf @@ -17,4 +17,5 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32s2.conf b/boot/zephyr/socs/esp32s2.conf index b2b405922a..7d3368bad0 100644 --- a/boot/zephyr/socs/esp32s2.conf +++ b/boot/zephyr/socs/esp32s2.conf @@ -16,4 +16,5 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32s3_procpu.conf b/boot/zephyr/socs/esp32s3_procpu.conf index b2b405922a..7d3368bad0 100644 --- a/boot/zephyr/socs/esp32s3_procpu.conf +++ b/boot/zephyr/socs/esp32s3_procpu.conf @@ -16,4 +16,5 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/nrf54l15_cpuapp.conf b/boot/zephyr/socs/nrf54l15_cpuapp.conf new file mode 100644 index 0000000000..8db9d2d239 --- /dev/null +++ b/boot/zephyr/socs/nrf54l15_cpuapp.conf @@ -0,0 +1,3 @@ +# Link Time Optimizations +CONFIG_ISR_TABLES_LOCAL_DECLARATION=y +CONFIG_LTO=y diff --git a/docs/release-notes.md b/docs/release-notes.md index e5480b9a6a..1eebd41a09 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -66,6 +66,16 @@ MCUboot is compiled without support for them - Added support for devices that do not require erase prior to write operation. - Add corrections to the max app size calculations. +- Fixed issue with swap using scratch mode that would cause the + primary image to be corrupt and unbootable after an update if the + device was rebooted whilst the scratch area was being erased. +- Fixed issue with serial recovery if canonical CBOR mode was + enabled. +- Fixed issue with serial recovery set image state not checking + primary slot images. +- Fixed issue with watchdog not being fed during flash erase + operations, which could cause the watchdog to time out on long + erase operations and prevent firmware updates from being possible. ## Version 2.1.0