Skip to content

Commit 728ea64

Browse files
committed
mgmt: Handle manifest-based states
Add routines to parse and check manifest state. Signed-off-by: Tomasz Chyrowicz <tomasz.chyrowicz@nordicsemi.no>
1 parent e222a17 commit 728ea64

File tree

2 files changed

+159
-3
lines changed

2 files changed

+159
-3
lines changed

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

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

34+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
35+
#include <bootutil/bootutil_public.h>
36+
#include <bootutil/mcuboot_manifest.h>
37+
#endif
38+
3439
#ifdef CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS
3540
#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
3641
#include <mgmt/mcumgr/transport/smp_internal.h>
@@ -274,6 +279,126 @@ int img_mgmt_active_image(void)
274279
return ACTIVE_IMAGE_IS;
275280
}
276281

282+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
283+
/**
284+
* Checks whether the manifest of the image in the specified slot can be used for booting.
285+
*
286+
* @param slot The slot to check the manifest for.
287+
*
288+
* @return true if the manifest can be used, false otherwise.
289+
*/
290+
static bool boot_check_manifest(enum boot_slot slot)
291+
{
292+
struct image_header hdr;
293+
struct image_tlv tlv;
294+
size_t data_off;
295+
size_t data_end;
296+
bool manifest_found;
297+
uint8_t erased_val;
298+
uint32_t erased_val_32;
299+
struct mcuboot_manifest tmp_manifest;
300+
uint8_t hash[IMAGE_HASH_SIZE];
301+
int rc;
302+
int image_slot = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER * BOOT_SLOT_COUNT + slot;
303+
304+
rc = img_mgmt_erased_val(image_slot, &erased_val);
305+
if (rc != 0) {
306+
return false;
307+
}
308+
309+
rc = img_mgmt_read(image_slot,
310+
boot_get_image_start_offset(img_mgmt_flash_area_id(image_slot)),
311+
&hdr, sizeof(hdr));
312+
if (rc != 0) {
313+
return false;
314+
}
315+
316+
erased_val_32 = ERASED_VAL_32(erased_val);
317+
if (hdr.ih_magic == IMAGE_MAGIC) {
318+
/* Valid header */
319+
} else if (hdr.ih_magic == erased_val_32) {
320+
return false;
321+
} else {
322+
return false;
323+
}
324+
325+
/* Read the image's TLVs. We try to find manifest only inside the protected TLVs.
326+
* If the manifest is missing, the image is considered invalid.
327+
*/
328+
data_off = hdr.ih_hdr_size + hdr.ih_img_size +
329+
boot_get_image_start_offset(img_mgmt_flash_area_id(image_slot));
330+
331+
rc = img_mgmt_find_tlvs(image_slot, &data_off, &data_end, IMAGE_TLV_PROT_INFO_MAGIC);
332+
if (rc != 0) {
333+
return false;
334+
}
335+
336+
manifest_found = false;
337+
while (data_off + sizeof(tlv) <= data_end) {
338+
rc = img_mgmt_read(image_slot, data_off, &tlv, sizeof(tlv));
339+
if (rc != 0) {
340+
return false;
341+
}
342+
if (tlv.it_type == 0xff && tlv.it_len == 0xffff) {
343+
return false;
344+
}
345+
if ((tlv.it_type != IMAGE_TLV_MANIFEST) || (tlv.it_len != sizeof(struct mcuboot_manifest))) {
346+
/* Non-manifest TLV. Skip it. */
347+
data_off += sizeof(tlv) + tlv.it_len;
348+
continue;
349+
}
350+
351+
if (manifest_found) {
352+
/* More than one manifest. */
353+
return false;
354+
}
355+
manifest_found = true;
356+
357+
data_off += sizeof(tlv);
358+
if (data_off + sizeof(struct mcuboot_manifest) > data_end) {
359+
return false;
360+
}
361+
rc = img_mgmt_read(image_slot, data_off, &tmp_manifest, sizeof(struct mcuboot_manifest));
362+
if (rc != 0) {
363+
return false;
364+
}
365+
}
366+
367+
if (!manifest_found) {
368+
return false;
369+
}
370+
371+
for (size_t i = 0; i < BOOT_IMAGE_NUMBER; i++) {
372+
if (CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER == i) {
373+
continue;
374+
}
375+
376+
rc = img_mgmt_read_info(i * BOOT_SLOT_COUNT + slot, NULL, hash, NULL);
377+
if ((rc == 0) && bootutil_verify_manifest_image_hash(&tmp_manifest, hash, i)) {
378+
/* Hash matches */
379+
continue;
380+
}
381+
382+
#if !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) && \
383+
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) && \
384+
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
385+
/* In SWAP modes, the image may be placed in either primary or secondary slot. */
386+
rc = img_mgmt_read_info(i * BOOT_SLOT_COUNT + ((slot + 1) % BOOT_SLOT_COUNT), NULL,
387+
hash, NULL);
388+
if ((rc == 0) && bootutil_verify_manifest_image_hash(&tmp_manifest, hash, i)) {
389+
/* Hash matches */
390+
continue;
391+
}
392+
#endif
393+
394+
LOG_ERR("Manifest hash does not match image %d hash", i);
395+
return false;
396+
}
397+
398+
return true;
399+
}
400+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
401+
277402
/*
278403
* Reads the version and build hash from the specified image slot.
279404
*/
@@ -317,6 +442,12 @@ int img_mgmt_read_info(int image_slot, struct image_version *ver, uint8_t *hash,
317442

318443
if (flags != NULL) {
319444
*flags = hdr.ih_flags;
445+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
446+
/* Mark slot as unbootable if manifest is not satisfied. */
447+
if (!boot_check_manifest(image_slot % SLOTS_PER_IMAGE)) {
448+
*flags |= IMAGE_F_NON_BOOTABLE;
449+
}
450+
#endif
320451
}
321452

322453
/* Read the image's TLVs. We first try to find the protected TLVs, if the protected

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

Lines changed: 28 additions & 3 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.
@@ -258,18 +270,23 @@ int img_mgmt_get_next_boot_slot(int image, enum img_mgmt_next_boot_type *type)
258270
{
259271
struct image_version aver;
260272
struct image_version over;
261-
int active_slot = img_mgmt_active_slot(image);
262-
int other_slot = img_mgmt_get_opposite_slot(active_slot);
263273
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
264274
int active_slot_state;
265275
int other_slot_state;
266276
#endif /* defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) */
267277
enum img_mgmt_next_boot_type lt = NEXT_BOOT_TYPE_NORMAL;
268-
int return_slot = active_slot;
269278

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

285+
int active_slot = img_mgmt_active_slot(image);
286+
int other_slot = img_mgmt_get_opposite_slot(active_slot);
271287
int rcs = img_mgmt_read_info(other_slot, &over, NULL, NULL);
272288
int rca = img_mgmt_read_info(active_slot, &aver, NULL, NULL);
289+
int return_slot = active_slot;
273290

274291
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
275292
active_slot_state = read_directxip_state(active_slot);
@@ -364,6 +381,14 @@ int img_mgmt_get_next_boot_slot(int image, enum img_mgmt_next_boot_type *type)
364381
*type = lt;
365382
}
366383

384+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
385+
if (return_slot != active_slot) {
386+
return_slot = img_mgmt_get_opposite_slot(img_mgmt_active_slot(query_image));
387+
} else {
388+
return_slot = img_mgmt_active_slot(query_image);
389+
}
390+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
391+
367392
return return_slot;
368393
}
369394
#endif /* defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \

0 commit comments

Comments
 (0)