Skip to content

Commit 0d0fc70

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 0d0fc70

File tree

2 files changed

+148
-5
lines changed

2 files changed

+148
-5
lines changed

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

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

192197
ARG_UNUSED(area_sizes);
193198

194-
rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, &max_app_size, sizeof(max_app_size))
195-
199+
rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, &max_app_size, sizeof(max_app_size));
196200
if (rc < 0) {
197201
LOG_ERR("Failed to lookup max application size: %d", rc);
198202
} else if (rc > 0) {
@@ -274,6 +278,114 @@ int img_mgmt_active_image(void)
274278
return ACTIVE_IMAGE_IS;
275279
}
276280

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

318430
if (flags != NULL) {
319431
*flags = hdr.ih_flags;
432+
#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES
433+
/* Mark slot as unbootable if manifest is not satisfied. */
434+
if (!boot_check_manifest(image_slot % SLOTS_PER_IMAGE)) {
435+
*flags |= IMAGE_F_NON_BOOTABLE;
436+
}
437+
#endif
320438
}
321439

322440
/* 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)