Skip to content

Commit 0aefce2

Browse files
committed
[nrf noup] loader: Handle encrypted MCUboot updates
Use either load_address from the image header or the UUID identification to detect an encrypted MCUboot update candidate image. Ref: NCSDK-35089 Signed-off-by: Tomasz Chyrowicz <tomasz.chyrowicz@nordicsemi.no>
1 parent 69c7ba7 commit 0aefce2

4 files changed

Lines changed: 257 additions & 8 deletions

File tree

boot/bootutil/include/bootutil/mcuboot_uuid.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@ fih_ret boot_uuid_vid_match(const struct flash_area *fap, const struct image_uui
5757
*/
5858
fih_ret boot_uuid_cid_match(const struct flash_area *fap, const struct image_uuid *uuid_cid);
5959

60+
/**
61+
* @brief Find the image index and partition index for a given class ID and vendor ID.
62+
*
63+
* @param[in] cid The class ID to search for.
64+
* @param[in] vid The vendor ID to search for.
65+
* @param[out] image_index The index of the image found.
66+
* @param[out] partition_index The index of the partition found.
67+
*
68+
* @retval 0 on success,
69+
* @retval -EINVAL if the input parameters are invalid.
70+
* @retval -ENOENT if the image or partition is not found.
71+
*/
72+
int boot_uuid_find_image(const struct image_uuid *cid, const struct image_uuid *vid,
73+
size_t *image_index, size_t *partition_index);
74+
6075
#ifdef __cplusplus
6176
}
6277
#endif

boot/bootutil/src/loader.c

Lines changed: 148 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr);
9292
#include <load_ironside_se_conf.h>
9393
#endif
9494

95+
#if defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID)
96+
#include "bootutil/mcuboot_uuid.h"
97+
98+
#ifdef SECOND_STAGE_MCUBOOT_RUNNING_FROM_S0
99+
#define MCUBOOT_INACTIVE_PARTITION_INDEX 1
100+
#define MCUBOOT_ACTIVE_PARTITION_INDEX 0
101+
#else
102+
#define MCUBOOT_INACTIVE_PARTITION_INDEX 0
103+
#define MCUBOOT_ACTIVE_PARTITION_INDEX 1
104+
#endif
105+
#endif
106+
95107
#ifdef CONFIG_SOC_EARLY_RESET_HOOK
96108
void s2ram_designate_slot(uint8_t slot);
97109
#endif
@@ -1024,6 +1036,56 @@ static inline void sec_slot_cleanup_if_unusable(void)
10241036
#endif /* defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\
10251037
defined(MCUBOOT_IS_SECOND_STAGE) || defined(CONFIG_SOC_NRF5340_CPUAPP) */
10261038

1039+
#ifdef CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID
1040+
/**
1041+
* Read the image UUID from the TLV.
1042+
*
1043+
* @param[in] fap Pointer to the flash area structure.
1044+
* @param[in] hdr Pointer to the image header structure.
1045+
* @param[in] tlv_type The type of the TLV to read.
1046+
* @param[out] uuid Pointer to the image UUID structure.
1047+
*
1048+
* @return 0 on success,
1049+
* @retval -EINVAL if the input parameters are invalid.
1050+
* @retval -EIO if the TLV cannot be read.
1051+
* @retval -ENOENT if the TLV cannot be found.
1052+
*/
1053+
int read_image_uuid_tlv(const struct flash_area *fap,
1054+
const struct image_header *hdr,
1055+
uint16_t tlv_type,
1056+
struct image_uuid *uuid)
1057+
{
1058+
struct image_tlv_iter it;
1059+
uint32_t off;
1060+
uint16_t len;
1061+
int rc;
1062+
1063+
if ((fap == NULL) || (hdr == NULL) || (uuid == NULL)) {
1064+
return -EINVAL;
1065+
}
1066+
1067+
rc = bootutil_tlv_iter_begin(&it, hdr, fap, tlv_type, false);
1068+
if (rc != 0) {
1069+
return -ENOENT;
1070+
}
1071+
1072+
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
1073+
if (rc != 0) {
1074+
return -ENOENT;
1075+
}
1076+
1077+
if (len != sizeof(uuid->raw)) {
1078+
return -EINVAL;
1079+
}
1080+
1081+
if (flash_area_read(fap, off, uuid->raw, len) != 0) {
1082+
return -EIO;
1083+
}
1084+
1085+
return 0;
1086+
}
1087+
#endif /* CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID */
1088+
10271089
/**
10281090
* Determines which swap operation to perform, if any. If it is determined
10291091
* that a swap operation is required, the image in the secondary slot is checked
@@ -1038,12 +1100,25 @@ boot_validated_swap_type(struct boot_loader_state *state,
10381100
{
10391101
int swap_type;
10401102
FIH_DECLARE(fih_rc, FIH_FAILURE);
1103+
#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 \
1104+
&& !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) && defined(CONFIG_PCD_APP)
10411105
bool upgrade_valid = false;
1106+
#endif
10421107

10431108
#if defined(MCUBOOT_IS_SECOND_STAGE) || CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1
10441109
const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY);
10451110
struct image_header *hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY);
1111+
#if defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_LOAD_ADDRESS) || \
1112+
defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_RESET_VECTOR)
10461113
uint32_t internal_img_addr = 0;
1114+
#elif defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID)
1115+
struct image_uuid img_uuid_cid;
1116+
#ifdef MCUBOOT_UUID_VID
1117+
struct image_uuid img_uuid_vid;
1118+
#endif
1119+
size_t target_image = 0;
1120+
size_t target_partition = 0;
1121+
#endif
10471122
int rc = 0;
10481123
/* Patch needed for NCS. Since image 0 (the app) and image 1 (the other
10491124
* B1 slot S0 or S1) share the same secondary slot, we need to check
@@ -1055,8 +1130,10 @@ boot_validated_swap_type(struct boot_loader_state *state,
10551130
*/
10561131
NSIB_OWNED_UNSET(BOOT_CURR_IMG(state));
10571132

1133+
#if defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_LOAD_ADDRESS) || \
1134+
defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_RESET_VECTOR)
10581135
if (hdr->ih_magic == IMAGE_MAGIC) {
1059-
#ifdef MCUBOOT_CHECK_HEADER_LOAD_ADDRESS
1136+
#ifdef CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_LOAD_ADDRESS
10601137
internal_img_addr = hdr->ih_load_addr;
10611138
#else
10621139
rc = flash_area_read(secondary_fa, hdr->ih_hdr_size + RESET_OFFSET,
@@ -1124,7 +1201,62 @@ boot_validated_swap_type(struct boot_loader_state *state,
11241201
sec_slot_mark_assigned(state);
11251202
}
11261203

1127-
#endif /* MCUBOOT_IS_SECOND_STAGE || CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 */
1204+
#elif defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID)
1205+
if (hdr->ih_magic == IMAGE_MAGIC) {
1206+
rc = read_image_uuid_tlv(secondary_fa, hdr, IMAGE_TLV_UUID_CID, &img_uuid_cid);
1207+
if (rc != 0) {
1208+
return BOOT_SWAP_TYPE_NONE;
1209+
}
1210+
#ifdef MCUBOOT_UUID_VID
1211+
rc = read_image_uuid_tlv(secondary_fa, hdr, IMAGE_TLV_UUID_VID, &img_uuid_vid);
1212+
if (rc != 0) {
1213+
return BOOT_SWAP_TYPE_NONE;
1214+
}
1215+
#endif
1216+
1217+
sec_slot_touch(state);
1218+
1219+
rc = boot_uuid_find_image(&img_uuid_cid,
1220+
#ifdef MCUBOOT_UUID_VID
1221+
&img_uuid_vid,
1222+
#else
1223+
NULL,
1224+
#endif
1225+
&target_image, &target_partition);
1226+
if (rc != 0) {
1227+
/* Unable to find a matching image index. */
1228+
BOOT_LOG_ERR("Image in slot does not match any known UUID");
1229+
flash_area_erase(secondary_fa, 0, secondary_fa->fa_size);
1230+
sec_slot_untouch(state);
1231+
BOOT_LOG_ERR("Cleaned-up secondary slot of image %d", BOOT_CURR_IMG(state));
1232+
return BOOT_SWAP_TYPE_FAIL;
1233+
}
1234+
1235+
if (target_image == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) {
1236+
/* This is a valid network core update candidate. */
1237+
#ifdef MCUBOOT_IS_SECOND_STAGE
1238+
} else if ((target_image == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) &&
1239+
(target_partition == MCUBOOT_INACTIVE_PARTITION_INDEX)) {
1240+
/* This is a valid MCUboot update candidate. */
1241+
NSIB_OWNED_SET(BOOT_CURR_IMG(state));
1242+
} else if ((target_image == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) &&
1243+
(target_partition == MCUBOOT_ACTIVE_PARTITION_INDEX)) {
1244+
/* NSIB upgrade but for the wrong slot, must be erased */
1245+
BOOT_LOG_ERR("Image in slot is for wrong s0/s1 image");
1246+
flash_area_erase(secondary_fa, 0, secondary_fa->fa_size);
1247+
sec_slot_untouch(state);
1248+
BOOT_LOG_ERR("Cleaned-up secondary slot of image %d", BOOT_CURR_IMG(state));
1249+
return BOOT_SWAP_TYPE_FAIL;
1250+
#endif /* MCUBOOT_IS_SECOND_STAGE */
1251+
} else {
1252+
/* The image in the secondary slot is not intended for any */
1253+
return BOOT_SWAP_TYPE_NONE;
1254+
}
1255+
1256+
sec_slot_mark_assigned(state);
1257+
}
1258+
#endif /* CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID */
1259+
#endif /* defined(MCUBOOT_IS_SECOND_STAGE) || CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 */
11281260

11291261
swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
11301262
if (BOOT_IS_UPGRADE(swap_type)) {
@@ -1138,8 +1270,11 @@ boot_validated_swap_type(struct boot_loader_state *state,
11381270
} else {
11391271
swap_type = BOOT_SWAP_TYPE_FAIL;
11401272
}
1273+
#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 \
1274+
&& !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) && defined(CONFIG_PCD_APP)
11411275
} else {
11421276
upgrade_valid = true;
1277+
#endif
11431278
}
11441279

11451280
#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 \
@@ -1148,8 +1283,17 @@ boot_validated_swap_type(struct boot_loader_state *state,
11481283
* update and indicate to the caller of this function that no update is
11491284
* available
11501285
*/
1151-
if (upgrade_valid && internal_img_addr >= NETCPU_APP_SLOT_OFFSET &&
1152-
internal_img_addr < NETCPU_APP_SLOT_END) {
1286+
if (upgrade_valid
1287+
#if defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_LOAD_ADDRESS) || \
1288+
defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_RESET_VECTOR)
1289+
&& (internal_img_addr >= NETCPU_APP_SLOT_OFFSET)
1290+
&& (internal_img_addr < NETCPU_APP_SLOT_END)
1291+
#elif defined(CONFIG_NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID)
1292+
&& (target_image == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER)
1293+
#else
1294+
#error Unable to detect radio image update candidate.
1295+
#endif
1296+
) {
11531297
struct image_header *hdr = (struct image_header *)secondary_fa->fa_off;
11541298
uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size;
11551299
uint32_t *net_core_fw_addr = (uint32_t *)(vtable_addr);

boot/zephyr/Kconfig

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,36 @@ config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS
15381538
Time between image validation attempts, in milliseconds.
15391539
Allows for recovery from transient bit flips or similar situations.
15401540

1541+
choice NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE
1542+
prompt "Secondary slot image resolve method"
1543+
depends on MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1
1544+
default NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID if MCUBOOT_UUID_CID
1545+
default NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_LOAD_ADDRESS if MCUBOOT_CHECK_HEADER_LOAD_ADDRESS
1546+
default NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_RESET_VECTOR
1547+
1548+
config NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_RESET_VECTOR
1549+
bool "Reset vector"
1550+
help
1551+
The bootloader will use the reset vector, read from image, to assign image for a given
1552+
secondary slot.
1553+
This is the default behavior.
1554+
1555+
config NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_LOAD_ADDRESS
1556+
bool "Load address"
1557+
depends on MCUBOOT_CHECK_HEADER_LOAD_ADDRESS
1558+
help
1559+
The bootloader will use the load address, from the image header,
1560+
to assign image for a given secondary slot.
1561+
1562+
config NCS_MCUBOOT_SECONDARY_SLOT_IMAGE_RESOLVE_UUID
1563+
bool "Class ID (and Vendor ID if enabled) UUIDs"
1564+
depends on MCUBOOT_UUID_CID
1565+
help
1566+
The bootloader will use the Class ID and Vendor ID UUIDs, read from image, to assign
1567+
image for a given secondary slot.
1568+
1569+
endchoice
1570+
15411571
config PM_APP_ALIGNMENT
15421572
hex
15431573
default 0x1000 if SOC_SERIES_NRF54L

boot/zephyr/uuid/uuid.c

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,29 @@ static bool boot_uuid_compare(const struct image_uuid *uuid1, const struct image
1414
return false;
1515
}
1616

17-
return memcmp(uuid1->raw, uuid2->raw, ARRAY_SIZE(uuid1->raw)) == 0;
17+
return memcmp(uuid1->raw, uuid2->raw, sizeof(uuid1->raw)) == 0;
1818
}
1919

20-
fih_ret boot_uuid_init(void)
20+
#ifdef CONFIG_MCUBOOT_UUID_VID
21+
static bool vid_matches_map_entry(const struct image_uuid *vid, const struct uuid_map_entry *entry)
2122
{
22-
FIH_RET(FIH_SUCCESS);
23+
const struct uuid_map_entry *vid_map = NULL;
24+
size_t n_entries = boot_uuid_vid_map_get(&vid_map);
25+
26+
if (vid == NULL) {
27+
return false;
28+
}
29+
30+
for (size_t i = 0; i < n_entries; i++) {
31+
if ((vid_map[i].dev == entry->dev) && (vid_map[i].off == entry->off) &&
32+
(vid_map[i].size == entry->size) && boot_uuid_compare(vid, &vid_map[i].uuid)) {
33+
return true;
34+
}
35+
}
36+
37+
return false;
2338
}
2439

25-
#ifdef CONFIG_MCUBOOT_UUID_VID
2640
fih_ret boot_uuid_vid_match(const struct flash_area *fap, const struct image_uuid *uuid_vid)
2741
{
2842
const struct uuid_map_entry *map = NULL;
@@ -82,4 +96,50 @@ fih_ret boot_uuid_cid_match(const struct flash_area *fap, const struct image_uui
8296

8397
FIH_RET(FIH_FAILURE);
8498
}
99+
100+
int boot_uuid_find_image(const struct image_uuid *cid, const struct image_uuid *vid,
101+
size_t *image_index, size_t *partition_index)
102+
{
103+
const struct uuid_map_entry *cid_map = NULL;
104+
size_t n_entries;
105+
106+
if ((cid == NULL) || (image_index == NULL) || (partition_index == NULL)) {
107+
return -EINVAL;
108+
}
109+
110+
#ifdef MCUBOOT_UUID_VID
111+
if (vid == NULL) {
112+
return -EINVAL;
113+
}
114+
#endif
115+
116+
n_entries = boot_uuid_cid_map_get(&cid_map);
117+
if ((n_entries == 0) || (cid_map == NULL)) {
118+
return -ENOENT;
119+
}
120+
121+
for (size_t i = 0; i < n_entries; i++) {
122+
if (!boot_uuid_compare(cid, &cid_map[i].uuid)) {
123+
continue;
124+
}
125+
126+
#ifdef MCUBOOT_UUID_VID
127+
if (!vid_matches_map_entry(vid, &cid_map[i])) {
128+
continue;
129+
}
130+
#endif
131+
132+
*image_index = cid_map[i].image_index;
133+
*partition_index = cid_map[i].partition_index;
134+
135+
return 0;
136+
}
137+
138+
return -ENOENT;
139+
}
85140
#endif /* CONFIG_MCUBOOT_UUID_CID */
141+
142+
fih_ret boot_uuid_init(void)
143+
{
144+
FIH_RET(FIH_SUCCESS);
145+
}

0 commit comments

Comments
 (0)