Skip to content

Commit 5b7bccf

Browse files
committed
boot: bootutil: swap_offset: Fix not including unprotected TLVs
Fixes an issue whereby the size of unprotected TLVs were not included in the size of the image to swap. Because this information is not present in the MCUboot header and because swap using offset includes swapping data that might mangle this area, extra space in the swap status trailer needs to be reserved and used Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
1 parent ee9efe0 commit 5b7bccf

File tree

5 files changed

+99
-7
lines changed

5 files changed

+99
-7
lines changed

boot/bootutil/src/bootutil_misc.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ boot_trailer_info_sz(void)
126126
#endif
127127
/* swap_type + copy_done + image_ok + swap_size */
128128
BOOT_MAX_ALIGN * 4 +
129+
#ifdef MCUBOOT_SWAP_USING_OFFSET
130+
/* TLV size for both slots */
131+
BOOT_MAX_ALIGN +
132+
#endif
129133
BOOT_MAGIC_ALIGN_SIZE
130134
);
131135
}
@@ -361,6 +365,27 @@ boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size)
361365
return rc;
362366
}
363367

368+
#ifdef MCUBOOT_SWAP_USING_OFFSET
369+
int
370+
boot_read_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t *tlv_size_primary,
371+
uint16_t *tlv_size_secondary)
372+
{
373+
uint32_t off;
374+
uint32_t combined_tlv_sizes = 0;
375+
int rc;
376+
377+
off = boot_unprotected_tlv_sizes_off(fap);
378+
rc = flash_area_read(fap, off, &combined_tlv_sizes, sizeof(combined_tlv_sizes));
379+
380+
if (rc == 0) {
381+
*tlv_size_primary = (uint16_t)(combined_tlv_sizes & 0xffff);
382+
*tlv_size_secondary = (uint16_t)((combined_tlv_sizes & 0xffff0000) >> 16);
383+
}
384+
385+
return rc;
386+
}
387+
#endif
388+
364389
#ifdef MCUBOOT_ENC_IMAGES
365390
int
366391
boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs)
@@ -405,6 +430,25 @@ boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
405430
return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
406431
}
407432

433+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
434+
int
435+
boot_write_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t tlv_size_primary,
436+
uint16_t tlv_size_secondary)
437+
{
438+
uint32_t off;
439+
uint32_t tlv_sizes_combined;
440+
441+
off = boot_unprotected_tlv_sizes_off(fap);
442+
tlv_sizes_combined = ((uint32_t)tlv_size_secondary << 16) | (uint32_t)tlv_size_primary;
443+
BOOT_LOG_DBG("writing unprotected_tlv_sizes; fa_id=%d off=0x%lx (0x%lx) vals=0x%x,0x%x (0x%lx)",
444+
flash_area_get_id(fap), (unsigned long)off,
445+
((unsigned long)flash_area_get_off(fap) + off), tlv_size_primary,
446+
tlv_size_secondary, (unsigned long)tlv_sizes_combined);
447+
return boot_write_trailer(fap, off, (const uint8_t *)&tlv_sizes_combined,
448+
sizeof(tlv_sizes_combined));
449+
}
450+
#endif
451+
408452
#ifdef MCUBOOT_ENC_IMAGES
409453
int
410454
boot_write_enc_keys(const struct flash_area *fap, const struct boot_status *bs)

boot/bootutil/src/bootutil_misc.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,24 @@ boot_copy_done_off(const struct flash_area *fap)
4343
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
4444
}
4545

46+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
47+
static inline uint32_t
48+
boot_unprotected_tlv_sizes_off(const struct flash_area *fap)
49+
{
50+
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
51+
}
52+
53+
static inline uint32_t
54+
boot_swap_size_off(const struct flash_area *fap)
55+
{
56+
return boot_unprotected_tlv_sizes_off(fap) - BOOT_MAX_ALIGN;
57+
}
58+
#else
4659
static inline uint32_t
4760
boot_swap_size_off(const struct flash_area *fap)
4861
{
4962
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
5063
}
64+
#endif
5165

5266
#endif /* H_BOOTUTIL_MISC_ */

boot/bootutil/src/bootutil_priv.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ struct boot_loader_state {
242242
const struct flash_area *area;
243243
boot_sector_t *sectors;
244244
uint32_t num_sectors;
245+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
246+
uint16_t unprotected_tlv_size;
247+
#endif
245248
} imgs[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
246249

247250
#if MCUBOOT_SWAP_USING_SCRATCH
@@ -342,6 +345,12 @@ int boot_write_trailer(const struct flash_area *fap, uint32_t off,
342345
int boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
343346
uint8_t flag_val);
344347
int boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size);
348+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
349+
int boot_write_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t tlv_size_primary,
350+
uint16_t tlv_size_secondary);
351+
int boot_read_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t *tlv_size_primary,
352+
uint16_t *tlv_size_secondary);
353+
#endif
345354
int boot_slots_compatible(struct boot_loader_state *state);
346355
uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz);
347356
int boot_read_image_header(struct boot_loader_state *state, int slot,
@@ -479,6 +488,7 @@ static inline bool boot_u16_safe_add(uint16_t *dest, uint16_t a, uint16_t b)
479488
#endif
480489
#define BOOT_IMG(state, slot) ((state)->imgs[BOOT_CURR_IMG(state)][(slot)])
481490
#define BOOT_IMG_AREA(state, slot) (BOOT_IMG(state, slot).area)
491+
#define BOOT_IMG_UNPROTECTED_TLV_SIZE(state, slot) (BOOT_IMG(state, slot).unprotected_tlv_size)
482492
#define BOOT_WRITE_SZ(state) ((state)->write_sz[BOOT_CURR_IMG(state)])
483493
#define BOOT_SWAP_TYPE(state) ((state)->swap_type[BOOT_CURR_IMG(state)])
484494
#define BOOT_TLV_OFF(hdr) ((hdr)->ih_hdr_size + (hdr)->ih_img_size)

boot/bootutil/src/swap_misc.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* SPDX-License-Identifier: Apache-2.0
33
*
44
* Copyright (c) 2019 JUUL Labs
5+
* Copyright (c) 2025 Nordic Semiconductor ASA
56
*
67
* Licensed under the Apache License, Version 2.0 (the "License");
78
* you may not use this file except in compliance with the License.
@@ -136,6 +137,13 @@ swap_status_init(const struct boot_loader_state *state,
136137
rc = boot_write_swap_size(fap, bs->swap_size);
137138
assert(rc == 0);
138139

140+
#ifdef MCUBOOT_SWAP_USING_OFFSET
141+
rc = boot_write_unprotected_tlv_sizes(fap,
142+
BOOT_IMG_UNPROTECTED_TLV_SIZE(state, BOOT_SLOT_PRIMARY),
143+
BOOT_IMG_UNPROTECTED_TLV_SIZE(state, BOOT_SLOT_SECONDARY));
144+
assert(rc == 0);
145+
#endif
146+
139147
#ifdef MCUBOOT_ENC_IMAGES
140148
rc = boot_write_enc_keys(fap, bs);
141149
#endif
@@ -243,5 +251,4 @@ swap_set_image_ok(uint8_t image_index)
243251
return rc;
244252
}
245253

246-
247254
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) */

boot/bootutil/src/swap_offset.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -593,12 +593,20 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs,
593593
const struct flash_area *fap_pri = NULL;
594594
const struct flash_area *fap_sec = NULL;
595595
int rc;
596+
uint16_t unprotected_tlv_size_pri;
597+
uint16_t unprotected_tlv_size_sec;
596598

597599
BOOT_LOG_INF("Starting swap using offset algorithm.");
598600

599601
last_idx = find_last_idx(state, copy_size);
600602
sector_sz = boot_img_sector_size(state, BOOT_SLOT_PRIMARY, 0);
601603

604+
fap_pri = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY);
605+
assert(fap_pri != NULL);
606+
607+
fap_sec = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY);
608+
assert(fap_sec != NULL);
609+
602610
/* When starting a new swap upgrade, check that there is enough space */
603611
if (boot_status_is_reset(bs)) {
604612
sz = 0;
@@ -623,12 +631,6 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs,
623631
}
624632
}
625633

626-
fap_pri = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY);
627-
assert(fap_pri != NULL);
628-
629-
fap_sec = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY);
630-
assert(fap_sec != NULL);
631-
632634
fixup_revert(state, bs, fap_sec);
633635

634636
/* Init areas for storing swap status */
@@ -647,14 +649,24 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs,
647649
assert(rc == 0);
648650
}
649651

652+
/* Read the unprotected TLV sizes from the boot swap status area, this information might get
653+
* jangled if rebooted during an update so it needs to be stored in this area for safe
654+
* retrieval
655+
*/
656+
boot_read_unprotected_tlv_sizes(fap_pri, &unprotected_tlv_size_pri, &unprotected_tlv_size_sec);
657+
BOOT_LOG_DBG("Unprotected TLV sizes image=%d: pri=%d, sec=%d", BOOT_CURR_IMG(state),
658+
unprotected_tlv_size_pri, unprotected_tlv_size_sec);
659+
650660
bs->op = BOOT_STATUS_OP_SWAP;
651661
idx = 0;
652662
used_sectors_pri = ((state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_PRIMARY].hdr.ih_hdr_size +
663+
unprotected_tlv_size_pri +
653664
state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_PRIMARY].hdr.ih_protect_tlv_size +
654665
state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_PRIMARY].hdr.ih_img_size) + sector_sz - 1) /
655666
sector_sz;
656667
used_sectors_sec = ((state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_SECONDARY].hdr.ih_hdr_size +
657668
state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_SECONDARY].hdr.ih_protect_tlv_size +
669+
unprotected_tlv_size_sec +
658670
state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_SECONDARY].hdr.ih_img_size) + sector_sz - 1) /
659671
sector_sz;
660672

@@ -770,6 +782,11 @@ int boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *si
770782
goto done;
771783
}
772784

785+
/* This is needed as unprotected TLV size cannot be calculated once a swap has been started,
786+
* it is only able to be properly calculated when images are in pristine states
787+
*/
788+
BOOT_IMG_UNPROTECTED_TLV_SIZE(state, slot) = info.it_tlv_tot;
789+
773790
*size = off + protect_tlv_size + info.it_tlv_tot;
774791
rc = 0;
775792

0 commit comments

Comments
 (0)