Skip to content

Commit f18dfe9

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 eca54e8 commit f18dfe9

File tree

2 files changed

+144
-6
lines changed

2 files changed

+144
-6
lines changed

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

Lines changed: 113 additions & 2 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>
@@ -191,8 +195,7 @@ static bool img_mgmt_slot_max_size(size_t *area_sizes, zcbor_state_t *zse)
191195

192196
ARG_UNUSED(area_sizes);
193197

194-
rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, &max_app_size, sizeof(max_app_size))
195-
198+
rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, &max_app_size, sizeof(max_app_size));
196199
if (rc < 0) {
197200
LOG_ERR("Failed to lookup max application size: %d", rc);
198201
} else if (rc > 0) {
@@ -380,6 +383,114 @@ int img_mgmt_read_info(int image_slot, struct image_version *ver, uint8_t *hash,
380383
return 0;
381384
}
382385

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

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

Lines changed: 31 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,10 +235,12 @@ 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;
229241

242+
fa_id = img_mgmt_flash_area_id(slot);
243+
230244
__ASSERT(fa_id != -1, "Could not map slot to area ID");
231245

232246
rc = flash_area_open(fa_id, &fa);
@@ -258,18 +272,23 @@ int img_mgmt_get_next_boot_slot(int image, enum img_mgmt_next_boot_type *type)
258272
{
259273
struct image_version aver;
260274
struct image_version over;
261-
int active_slot = img_mgmt_active_slot(image);
262-
int other_slot = img_mgmt_get_opposite_slot(active_slot);
263275
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
264276
int active_slot_state;
265277
int other_slot_state;
266278
#endif /* defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) */
267279
enum img_mgmt_next_boot_type lt = NEXT_BOOT_TYPE_NORMAL;
268-
int return_slot = active_slot;
269280

281+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
282+
/* If manifest-based updates are used, only the manifest image is considered. */
283+
int query_image = image;
284+
image = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER;
285+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
270286

287+
int active_slot = img_mgmt_active_slot(image);
288+
int other_slot = img_mgmt_get_opposite_slot(active_slot);
271289
int rcs = img_mgmt_read_info(other_slot, &over, NULL, NULL);
272290
int rca = img_mgmt_read_info(active_slot, &aver, NULL, NULL);
291+
int return_slot = active_slot;
273292

274293
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
275294
active_slot_state = read_directxip_state(active_slot);
@@ -364,6 +383,14 @@ int img_mgmt_get_next_boot_slot(int image, enum img_mgmt_next_boot_type *type)
364383
*type = lt;
365384
}
366385

386+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
387+
if (return_slot != active_slot) {
388+
return_slot = img_mgmt_get_opposite_slot(img_mgmt_active_slot(query_image));
389+
} else {
390+
return_slot = img_mgmt_active_slot(query_image);
391+
}
392+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
393+
367394
return return_slot;
368395
}
369396
#endif /* defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \

0 commit comments

Comments
 (0)