Skip to content

Commit 2d1bac1

Browse files
hakonfamd3zd3z
authored andcommitted
add option for rollback protection
Depends on 'MCUBOOT_OVERWRITE_ONLY' option since swap info is not protected by signature Signed-off-by: Håkon Øye Amundsen <[email protected]>
1 parent e2acfae commit 2d1bac1

File tree

4 files changed

+77
-34
lines changed

4 files changed

+77
-34
lines changed

boot/bootutil/src/loader.c

+55-34
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,42 @@ boot_check_header_erased(struct boot_loader_state *state, int slot)
510510
return 0;
511511
}
512512

513+
#if (BOOT_IMAGE_NUMBER > 1) || \
514+
(defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
515+
/**
516+
* Check if the version of the image is not older than required.
517+
*
518+
* @param req Required minimal image version.
519+
* @param ver Version of the image to be checked.
520+
*
521+
* @return 0 if the version is sufficient, nonzero otherwise.
522+
*/
523+
static int
524+
boot_is_version_sufficient(struct image_version *req,
525+
struct image_version *ver)
526+
{
527+
if (ver->iv_major > req->iv_major) {
528+
return 0;
529+
}
530+
if (ver->iv_major < req->iv_major) {
531+
return BOOT_EBADVERSION;
532+
}
533+
/* The major version numbers are equal. */
534+
if (ver->iv_minor > req->iv_minor) {
535+
return 0;
536+
}
537+
if (ver->iv_minor < req->iv_minor) {
538+
return BOOT_EBADVERSION;
539+
}
540+
/* The minor version numbers are equal. */
541+
if (ver->iv_revision < req->iv_revision) {
542+
return BOOT_EBADVERSION;
543+
}
544+
545+
return 0;
546+
}
547+
#endif
548+
513549
/*
514550
* Check that there is a valid image in a slot
515551
*
@@ -541,6 +577,24 @@ boot_validate_slot(struct boot_loader_state *state, int slot,
541577
goto out;
542578
}
543579

580+
#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
581+
if (slot != BOOT_PRIMARY_SLOT) {
582+
/* Check if version of secondary slot is sufficient */
583+
rc = boot_is_version_sufficient(
584+
&boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver,
585+
&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver);
586+
if (rc != 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
587+
BOOT_LOG_ERR("insufficient version in secondary slot");
588+
flash_area_erase(fap, 0, fap->fa_size);
589+
/* Image in the secondary slot does not satisfy version requirement.
590+
* Erase the image and continue booting from the primary slot.
591+
*/
592+
rc = 1;
593+
goto out;
594+
}
595+
}
596+
#endif
597+
544598
if (!boot_is_header_valid(hdr, fap) || boot_image_check(state, hdr, fap, bs)) {
545599
if (slot != BOOT_PRIMARY_SLOT) {
546600
flash_area_erase(fap, 0, fap->fa_size);
@@ -552,7 +606,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot,
552606
BOOT_LOG_ERR("Image in the %s slot is not valid!",
553607
(slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
554608
#endif
555-
rc = -1;
609+
rc = 1;
556610
goto out;
557611
}
558612

@@ -966,39 +1020,6 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
9661020
#endif
9671021

9681022
#if (BOOT_IMAGE_NUMBER > 1)
969-
/**
970-
* Check if the version of the image is not older than required.
971-
*
972-
* @param req Required minimal image version.
973-
* @param ver Version of the image to be checked.
974-
*
975-
* @return 0 if the version is sufficient, nonzero otherwise.
976-
*/
977-
static int
978-
boot_is_version_sufficient(struct image_version *req,
979-
struct image_version *ver)
980-
{
981-
if (ver->iv_major > req->iv_major) {
982-
return 0;
983-
}
984-
if (ver->iv_major < req->iv_major) {
985-
return BOOT_EBADVERSION;
986-
}
987-
/* The major version numbers are equal. */
988-
if (ver->iv_minor > req->iv_minor) {
989-
return 0;
990-
}
991-
if (ver->iv_minor < req->iv_minor) {
992-
return BOOT_EBADVERSION;
993-
}
994-
/* The minor version numbers are equal. */
995-
if (ver->iv_revision < req->iv_revision) {
996-
return BOOT_EBADVERSION;
997-
}
998-
999-
return 0;
1000-
}
1001-
10021023
/**
10031024
* Check the image dependency whether it is satisfied and modify
10041025
* the swap type if necessary.

boot/zephyr/Kconfig

+10
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,14 @@ config UPDATEABLE_IMAGE_NUMBER
346346
help
347347
Enables support of multi image update.
348348

349+
config MCUBOOT_DOWNGRADE_PREVENTION
350+
bool "Downgrade prevention"
351+
depends on BOOT_UPGRADE_ONLY
352+
help
353+
Prevent downgrades by enforcing incrementing version numbers.
354+
When this option is set, any upgrade must have greater major version
355+
or greater minor version with equal major version. This mechanism
356+
only protects against some attacks against version downgrades (for
357+
example, a JTAG could be used to write an older version).
358+
349359
source "$ZEPHYR_BASE/Kconfig.zephyr"

boot/zephyr/include/mcuboot_config/mcuboot_config.h

+4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@
8989
#define MCUBOOT_IMAGE_NUMBER 1
9090
#endif
9191

92+
#ifdef CONFIG_MCUBOOT_DOWNGRADE_PREVENTION
93+
#define MCUBOOT_DOWNGRADE_PREVENTION 1
94+
#endif
95+
9296
/*
9397
* Enabling this option uses newer flash map APIs. This saves RAM and
9498
* avoids deprecated API usage.

docs/design.md

+8
Original file line numberDiff line numberDiff line change
@@ -942,3 +942,11 @@ state after dependency check.
942942
943943
For more information on adding dependency entries to an image,
944944
see: [imgtool](imgtool.md).
945+
946+
## [Downgrade Prevention](#downgrade-prevention)
947+
948+
Downgrade prevention is a feature which enforces that the new image must have a
949+
higher version number than the image it is replacing. This feature is enabled
950+
with the `MCUBOOT_DOWNGRADE_PREVENTION` option. Downgrade prevention is only
951+
available when the overwrite-based image update strategy is used
952+
(i.e. `MCUBOOT_OVERWRITE_ONLY` is set).

0 commit comments

Comments
 (0)