Add downgrade prevention for swaps

Currently, downgrade prevention was limited to overwrite only
builds (version check) or devices with hardware storage for
security counter.

This extends downgrade prevention to be used when swap update
is selected.
Unlike MCUBOOT_HW_ROLLBACK_PROT option it does not require user
code to provide external way to store security counter.
Security counter from slot 1 image is used for comparison.
With security counter usage it is possible to have limited
software rollback if security counter was not incremented.

It is possible to use image version where strict rule for
image version comparison prevents any downgrades.

Downgrade prevention is also added to mynewt configuration.

If image in slot 1 is marked as pending and downgrade prevention
is in place, image will be deleted to avoid check on next boot.

Signed-off-by: Jerzy Kasenberg <jerzy.kasenberg@codecoup.pl>
This commit is contained in:
Jerzy Kasenberg 2022-04-12 15:05:33 +02:00 committed by David Brown
parent 4e2cdfe82f
commit e3f895d7ef
4 changed files with 103 additions and 4 deletions

View File

@ -268,7 +268,6 @@ bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len)
#endif /* !MCUBOOT_HW_KEY */
#endif
#ifdef MCUBOOT_HW_ROLLBACK_PROT
/**
* Reads the value of an image's security counter.
*
@ -328,7 +327,6 @@ bootutil_get_img_security_cnt(struct image_header *hdr,
return 0;
}
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
/*
* Verify the integrity of the image.

View File

@ -616,7 +616,7 @@ boot_check_header_erased(struct boot_loader_state *state, int slot)
#if (BOOT_IMAGE_NUMBER > 1) || \
defined(MCUBOOT_DIRECT_XIP) || \
defined(MCUBOOT_RAM_LOAD) || \
(defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
defined(MCUBOOT_DOWNGRADE_PREVENTION)
/**
* Compare image version numbers not including the build number
*
@ -1905,6 +1905,60 @@ boot_update_hw_rollback_protection(struct boot_loader_state *state)
#endif
}
/**
* Checks test swap downgrade prevention conditions.
*
* Function called only for swap upgrades test run. It may prevent
* swap if slot 1 image has <= version number or < security counter
*
* @param state Boot loader status information.
*
* @return 0 - image can be swapped, -1 downgrade prevention
*/
static int
check_downgrade_prevention(struct boot_loader_state *state)
{
#if defined(MCUBOOT_DOWNGRADE_PREVENTION) && \
(defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH))
uint32_t security_counter[2];
int rc;
if (MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER) {
/* If there was security no counter in slot 0, allow swap */
rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 0).hdr),
BOOT_IMG(state, 0).area,
&security_counter[0]);
if (rc != 0) {
return 0;
}
/* If there is no security counter in slot 1, or it's lower than
* that of slot 0, prevent downgrade */
rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 1).hdr),
BOOT_IMG(state, 1).area,
&security_counter[1]);
if (rc != 0 || security_counter[0] > security_counter[1]) {
rc = -1;
}
}
else {
rc = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
&boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
}
if (rc < 0) {
/* Image in slot 0 prevents downgrade, delete image in slot 1 */
BOOT_LOG_INF("Image in slot 1 erased due to downgrade prevention");
flash_area_erase(BOOT_IMG(state, 1).area, 0,
flash_area_get_size(BOOT_IMG(state, 1).area));
} else {
rc = 0;
}
return rc;
#else
(void)state;
return 0;
#endif
}
fih_int
context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
{
@ -2033,7 +2087,13 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
case BOOT_SWAP_TYPE_NONE:
break;
case BOOT_SWAP_TYPE_TEST: /* fallthrough */
case BOOT_SWAP_TYPE_TEST:
if (check_downgrade_prevention(state) != 0) {
/* Downgrade prevented */
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
break;
}
/* fallthrough */
case BOOT_SWAP_TYPE_PERM: /* fallthrough */
case BOOT_SWAP_TYPE_REVERT:
rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,

View File

@ -85,6 +85,19 @@
#if MYNEWT_VAL(BOOTUTIL_BOOTSTRAP)
#define MCUBOOT_BOOTSTRAP 1
#endif
#if MYNEWT_VAL_CHOICE(BOOTUTIL_DOWNGRADE_PREVENTION, version)
#define MCUBOOT_DOWNGRADE_PREVENTION 1
/* MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER is used later as bool value so it is
* always defined, (unlike MCUBOOT_DOWNGRADE_PREVENTION which is only used in
* preprocessor condition and my be not defined) */
#define MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER 0
#elif MYNEWT_VAL_CHOICE(BOOTUTIL_DOWNGRADE_PREVENTION, security_counter)
#define MCUBOOT_DOWNGRADE_PREVENTION 1
#define MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER 1
#endif
#if MYNEWT_VAL(BOOTUTIL_HW_DOWNGRADE_PREVENTION)
#define MCUBOOT_HW_ROLLBACK_PROT 1
#endif
#if MYNEWT_VAL(MCUBOOT_MEASURED_BOOT)
#define MCUBOOT_MEASURED_BOOT 1

View File

@ -76,6 +76,34 @@ syscfg.defs:
BOOTUTIL_MAX_IMG_SECTORS:
description: 'Maximum number of sectors that are swapped.'
value: 128
BOOTUTIL_DOWNGRADE_PREVENTION:
description: >
Select downgrade prevention strategy.
- none downgrades are allowed
- version:
Prevent downgrades by enforcing incrementing version numbers.
When this option is set, any upgrade must have greater major version
or greater minor version with equal major version. This mechanism
only protects against some attacks against version downgrades (for
example, a JTAG could be used to write an older version).
- security_counter:
security counter is used for version eligibility check instead of pure
version. When this option is set, any upgrade must have greater or
equal security counter value.
Because of the acceptance of equal values it allows for software
downgrades to some extent.
choices:
- none
- version
- security_counter
value: none
BOOTUTIL_HW_ROLLBACK_PROT:
description: >
Prevent undesirable/malicious software downgrades. When this option is
set, any upgrade must have greater or equal security counter value.
Because of the acceptance of equal values it allows for software
downgrade to some extent
value: 0
BOOTUTIL_HAVE_LOGGING:
description: 'Enable serial logging'
value: 0