Skip to content

Commit 732b90c

Browse files
committed
mgmt: Handle manifest-based states
Add routines to parse and check manifest state. Signed-off-by: Tomasz Chyrowicz <[email protected]>
1 parent c2d8006 commit 732b90c

File tree

2 files changed

+152
-4
lines changed

2 files changed

+152
-4
lines changed

subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
#include <zephyr/dfu/flash_img.h>
3232
#endif
3333

34+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
35+
#include <bootutil/mcuboot_manifest.h>
36+
#endif
37+
3438
#ifdef CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS
3539
#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
3640
#include <mgmt/mcumgr/transport/smp_internal.h>
@@ -380,6 +384,114 @@ int img_mgmt_read_info(int image_slot, struct image_version *ver, uint8_t *hash,
380384
return 0;
381385
}
382386

387+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
388+
/**
389+
* Checks whether the manifest of the image in the specified slot can be used for booting.
390+
*
391+
* @param slot The slot to check the manifest for.
392+
*
393+
* @return true if the manifest can be used, false otherwise.
394+
*/
395+
bool boot_check_manifest(enum boot_slot slot)
396+
{
397+
struct image_header hdr;
398+
struct image_tlv tlv;
399+
size_t data_off;
400+
size_t data_end;
401+
bool manifest_found;
402+
uint8_t erased_val;
403+
uint32_t erased_val_32;
404+
struct mcuboot_manifest tmp_manifest;
405+
uint8_t hash[IMAGE_HASH_SIZE];
406+
int rc;
407+
int image_slot = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER * BOOT_SLOT_COUNT + slot;
408+
409+
rc = img_mgmt_erased_val(image_slot, &erased_val);
410+
if (rc != 0) {
411+
return false;
412+
}
413+
414+
rc = img_mgmt_read(image_slot,
415+
boot_get_image_start_offset(img_mgmt_flash_area_id(image_slot)),
416+
&hdr, sizeof(hdr));
417+
if (rc != 0) {
418+
return false;
419+
}
420+
421+
erased_val_32 = ERASED_VAL_32(erased_val);
422+
if (hdr.ih_magic == IMAGE_MAGIC) {
423+
/* Valid header */
424+
} else if (hdr.ih_magic == erased_val_32) {
425+
return false;
426+
} else {
427+
return false;
428+
}
429+
430+
/* Read the image's TLVs. We try to find manifest only inside the protected TLVs.
431+
* If the manifest is missing, the image is considered invalid.
432+
*/
433+
data_off = hdr.ih_hdr_size + hdr.ih_img_size +
434+
boot_get_image_start_offset(img_mgmt_flash_area_id(image_slot));
435+
436+
rc = img_mgmt_find_tlvs(image_slot, &data_off, &data_end, IMAGE_TLV_PROT_INFO_MAGIC);
437+
if (!rc) {
438+
return false;
439+
}
440+
441+
manifest_found = false;
442+
while (data_off + sizeof(tlv) <= data_end) {
443+
rc = img_mgmt_read(image_slot, data_off, &tlv, sizeof(tlv));
444+
if (rc != 0) {
445+
return false;
446+
}
447+
if (tlv.it_type == 0xff && tlv.it_len == 0xffff) {
448+
return false;
449+
}
450+
if ((tlv.it_type != IMAGE_TLV_MANIFEST) || (tlv.it_len != sizeof(struct mcuboot_manifest))) {
451+
/* Non-manifest TLV. Skip it. */
452+
data_off += sizeof(tlv) + tlv.it_len;
453+
continue;
454+
}
455+
456+
if (manifest_found) {
457+
/* More than one manifest. */
458+
return false;
459+
}
460+
manifest_found = true;
461+
462+
data_off += sizeof(tlv);
463+
if (data_off + sizeof(struct mcuboot_manifest) > data_end) {
464+
return false;
465+
}
466+
rc = img_mgmt_read(image_slot, data_off, &tmp_manifest, sizeof(struct mcuboot_manifest));
467+
if (rc != 0) {
468+
return false;
469+
}
470+
}
471+
472+
if (!manifest_found) {
473+
return false;
474+
}
475+
476+
for (size_t i = 0; i < BOOT_IMAGE_NUMBER; i++) {
477+
if (CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER == i) {
478+
continue;
479+
}
480+
481+
rc = img_mgmt_read_info(i * BOOT_SLOT_COUNT + slot, NULL, hash, NULL);
482+
if ((rc == 0) && bootutil_verify_manifest_image_hash(&tmp_manifest, hash, i)) {
483+
/* Hash matches */
484+
continue;
485+
}
486+
487+
LOG_ERR("Manifest hash does not match image %d hash", i);
488+
return false;
489+
}
490+
491+
return true;
492+
}
493+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
494+
383495
/*
384496
* Finds image given version number. Returns the slot number image is in,
385497
* or -1 if not found.

subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ img_mgmt_state_flags(int query_slot)
131131
int image = query_slot / 2; /* We support max 2 images for now */
132132
int active_slot = img_mgmt_active_slot(image);
133133

134+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
135+
/* If manifest-based updates are used, only the manifest image is considered. */
136+
image = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER;
137+
if (query_slot == active_slot) {
138+
active_slot = img_mgmt_active_slot(image);
139+
query_slot = active_slot;
140+
} else {
141+
active_slot = img_mgmt_active_slot(image);
142+
query_slot = img_mgmt_get_opposite_slot(active_slot);
143+
}
144+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
145+
134146
/* In case when MCUboot is configured for FW loader/updater mode, slots
135147
* can be either active or non-active. There is no concept of pending
136148
* or confirmed slots.
@@ -223,9 +235,29 @@ int img_mgmt_get_next_boot_slot(int image, enum img_mgmt_next_boot_type *type)
223235
static int read_directxip_state(int slot)
224236
{
225237
struct boot_swap_state bss;
226-
int fa_id = img_mgmt_flash_area_id(slot);
238+
int fa_id;
227239
const struct flash_area *fa;
228240
int rc = 0;
241+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
242+
int active_slot = img_mgmt_active_slot(slot / 2);
243+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
244+
245+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
246+
/* If manifest-based updates are used, only the manifest image is considered. */
247+
if (slot == active_slot) {
248+
slot = img_mgmt_active_slot(CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER);
249+
} else {
250+
slot = img_mgmt_get_opposite_slot(img_mgmt_active_slot(
251+
CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER));
252+
}
253+
254+
if (!boot_check_manifest(slot % 2)) {
255+
LOG_ERR("Failed to read manifest of slot %d with error %d", slot, rc);
256+
return -1;
257+
}
258+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
259+
260+
fa_id = img_mgmt_flash_area_id(slot);
229261

230262
__ASSERT(fa_id != -1, "Could not map slot to area ID");
231263

@@ -258,18 +290,22 @@ int img_mgmt_get_next_boot_slot(int image, enum img_mgmt_next_boot_type *type)
258290
{
259291
struct image_version aver;
260292
struct image_version over;
261-
int active_slot = img_mgmt_active_slot(image);
262-
int other_slot = img_mgmt_get_opposite_slot(active_slot);
263293
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
264294
int active_slot_state;
265295
int other_slot_state;
266296
#endif /* defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) */
267297
enum img_mgmt_next_boot_type lt = NEXT_BOOT_TYPE_NORMAL;
268-
int return_slot = active_slot;
269298

299+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
300+
/* If manifest-based updates are used, only the manifest image is considered. */
301+
image = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER;
302+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
270303

304+
int active_slot = img_mgmt_active_slot(image);
305+
int other_slot = img_mgmt_get_opposite_slot(active_slot);
271306
int rcs = img_mgmt_read_info(other_slot, &over, NULL, NULL);
272307
int rca = img_mgmt_read_info(active_slot, &aver, NULL, NULL);
308+
int return_slot = active_slot;
273309

274310
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
275311
active_slot_state = read_directxip_state(active_slot);

0 commit comments

Comments
 (0)