Skip to content

Commit 38e839f

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 0659a29 commit 38e839f

File tree

2 files changed

+160
-3
lines changed

2 files changed

+160
-3
lines changed

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

Lines changed: 129 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,124 @@ 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_INDEX * 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+
return false;
319+
}
320+
321+
/* Read the image's TLVs. We try to find manifest only inside the protected TLVs.
322+
* If the manifest is missing, the image is considered invalid.
323+
*/
324+
data_off = hdr.ih_hdr_size + hdr.ih_img_size +
325+
boot_get_image_start_offset(img_mgmt_flash_area_id(image_slot));
326+
327+
rc = img_mgmt_find_tlvs(image_slot, &data_off, &data_end, IMAGE_TLV_PROT_INFO_MAGIC);
328+
if (rc != 0) {
329+
return false;
330+
}
331+
332+
manifest_found = false;
333+
while (data_off + sizeof(tlv) <= data_end) {
334+
rc = img_mgmt_read(image_slot, data_off, &tlv, sizeof(tlv));
335+
if (rc != 0) {
336+
return false;
337+
}
338+
if (tlv.it_type == 0xff && tlv.it_len == 0xffff) {
339+
return false;
340+
}
341+
if ((tlv.it_type != IMAGE_TLV_MANIFEST) ||
342+
(tlv.it_len != sizeof(struct mcuboot_manifest))) {
343+
/* Non-manifest TLV. Skip it. */
344+
data_off += sizeof(tlv) + tlv.it_len;
345+
continue;
346+
}
347+
348+
if (manifest_found) {
349+
/* More than one manifest. */
350+
return false;
351+
}
352+
manifest_found = true;
353+
354+
data_off += sizeof(tlv);
355+
if (data_off + sizeof(struct mcuboot_manifest) > data_end) {
356+
return false;
357+
}
358+
rc = img_mgmt_read(image_slot, data_off, &tmp_manifest,
359+
sizeof(struct mcuboot_manifest));
360+
if (rc != 0) {
361+
return false;
362+
}
363+
}
364+
365+
if (!manifest_found) {
366+
return false;
367+
}
368+
369+
for (size_t i = 0; i < BOOT_IMAGE_NUMBER; i++) {
370+
if (i == CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_INDEX) {
371+
continue;
372+
}
373+
374+
rc = img_mgmt_read_info(i * BOOT_SLOT_COUNT + slot, NULL, hash, NULL);
375+
if ((rc == 0) && bootutil_verify_manifest_image_hash(&tmp_manifest, hash, i)) {
376+
/* Hash matches */
377+
continue;
378+
}
379+
380+
#if !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) && \
381+
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT) && \
382+
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
383+
/* In SWAP modes, the image may be placed in either primary or secondary slot. */
384+
rc = img_mgmt_read_info(i * BOOT_SLOT_COUNT + ((slot + 1) % BOOT_SLOT_COUNT), NULL,
385+
hash, NULL);
386+
if ((rc == 0) && bootutil_verify_manifest_image_hash(&tmp_manifest, hash, i)) {
387+
/* Hash matches */
388+
continue;
389+
}
390+
#endif
391+
392+
LOG_ERR("Manifest hash does not match image %d hash", i);
393+
return false;
394+
}
395+
396+
return true;
397+
}
398+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
399+
277400
/*
278401
* Reads the version and build hash from the specified image slot.
279402
*/
@@ -317,6 +440,12 @@ int img_mgmt_read_info(int image_slot, struct image_version *ver, uint8_t *hash,
317440

318441
if (flags != NULL) {
319442
*flags = hdr.ih_flags;
443+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
444+
/* Mark slot as unbootable if manifest is not satisfied. */
445+
if (!boot_check_manifest(image_slot % SLOTS_PER_IMAGE)) {
446+
*flags |= IMAGE_F_NON_BOOTABLE;
447+
}
448+
#endif
320449
}
321450

322451
/* 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: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,20 @@ 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, overwrite the image and slot with
136+
* the manifest image.
137+
*/
138+
image = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_INDEX;
139+
if (query_slot == active_slot) {
140+
active_slot = img_mgmt_active_slot(image);
141+
query_slot = active_slot;
142+
} else {
143+
active_slot = img_mgmt_active_slot(image);
144+
query_slot = img_mgmt_get_opposite_slot(active_slot);
145+
}
146+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
147+
134148
/* In case when MCUboot is configured for FW loader/updater mode, slots
135149
* can be either active or non-active. There is no concept of pending
136150
* or confirmed slots.
@@ -258,18 +272,24 @@ 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;
270284

285+
image = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_INDEX;
286+
#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */
287+
288+
int active_slot = img_mgmt_active_slot(image);
289+
int other_slot = img_mgmt_get_opposite_slot(active_slot);
271290
int rcs = img_mgmt_read_info(other_slot, &over, NULL, NULL);
272291
int rca = img_mgmt_read_info(active_slot, &aver, NULL, NULL);
292+
int return_slot = active_slot;
273293

274294
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
275295
active_slot_state = read_directxip_state(active_slot);
@@ -364,6 +384,14 @@ int img_mgmt_get_next_boot_slot(int image, enum img_mgmt_next_boot_type *type)
364384
*type = lt;
365385
}
366386

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

0 commit comments

Comments
 (0)