Skip to content

Commit e3f895d

Browse files
kasjerd3zd3z
authored andcommitted
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 <[email protected]>
1 parent 4e2cdfe commit e3f895d

File tree

4 files changed

+103
-4
lines changed

4 files changed

+103
-4
lines changed

boot/bootutil/src/image_validate.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,6 @@ bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len)
268268
#endif /* !MCUBOOT_HW_KEY */
269269
#endif
270270

271-
#ifdef MCUBOOT_HW_ROLLBACK_PROT
272271
/**
273272
* Reads the value of an image's security counter.
274273
*
@@ -328,7 +327,6 @@ bootutil_get_img_security_cnt(struct image_header *hdr,
328327

329328
return 0;
330329
}
331-
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
332330

333331
/*
334332
* Verify the integrity of the image.

boot/bootutil/src/loader.c

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ boot_check_header_erased(struct boot_loader_state *state, int slot)
616616
#if (BOOT_IMAGE_NUMBER > 1) || \
617617
defined(MCUBOOT_DIRECT_XIP) || \
618618
defined(MCUBOOT_RAM_LOAD) || \
619-
(defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
619+
defined(MCUBOOT_DOWNGRADE_PREVENTION)
620620
/**
621621
* Compare image version numbers not including the build number
622622
*
@@ -1905,6 +1905,60 @@ boot_update_hw_rollback_protection(struct boot_loader_state *state)
19051905
#endif
19061906
}
19071907

1908+
/**
1909+
* Checks test swap downgrade prevention conditions.
1910+
*
1911+
* Function called only for swap upgrades test run. It may prevent
1912+
* swap if slot 1 image has <= version number or < security counter
1913+
*
1914+
* @param state Boot loader status information.
1915+
*
1916+
* @return 0 - image can be swapped, -1 downgrade prevention
1917+
*/
1918+
static int
1919+
check_downgrade_prevention(struct boot_loader_state *state)
1920+
{
1921+
#if defined(MCUBOOT_DOWNGRADE_PREVENTION) && \
1922+
(defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH))
1923+
uint32_t security_counter[2];
1924+
int rc;
1925+
1926+
if (MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER) {
1927+
/* If there was security no counter in slot 0, allow swap */
1928+
rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 0).hdr),
1929+
BOOT_IMG(state, 0).area,
1930+
&security_counter[0]);
1931+
if (rc != 0) {
1932+
return 0;
1933+
}
1934+
/* If there is no security counter in slot 1, or it's lower than
1935+
* that of slot 0, prevent downgrade */
1936+
rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 1).hdr),
1937+
BOOT_IMG(state, 1).area,
1938+
&security_counter[1]);
1939+
if (rc != 0 || security_counter[0] > security_counter[1]) {
1940+
rc = -1;
1941+
}
1942+
}
1943+
else {
1944+
rc = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
1945+
&boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
1946+
}
1947+
if (rc < 0) {
1948+
/* Image in slot 0 prevents downgrade, delete image in slot 1 */
1949+
BOOT_LOG_INF("Image in slot 1 erased due to downgrade prevention");
1950+
flash_area_erase(BOOT_IMG(state, 1).area, 0,
1951+
flash_area_get_size(BOOT_IMG(state, 1).area));
1952+
} else {
1953+
rc = 0;
1954+
}
1955+
return rc;
1956+
#else
1957+
(void)state;
1958+
return 0;
1959+
#endif
1960+
}
1961+
19081962
fih_int
19091963
context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
19101964
{
@@ -2033,7 +2087,13 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
20332087
case BOOT_SWAP_TYPE_NONE:
20342088
break;
20352089

2036-
case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2090+
case BOOT_SWAP_TYPE_TEST:
2091+
if (check_downgrade_prevention(state) != 0) {
2092+
/* Downgrade prevented */
2093+
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
2094+
break;
2095+
}
2096+
/* fallthrough */
20372097
case BOOT_SWAP_TYPE_PERM: /* fallthrough */
20382098
case BOOT_SWAP_TYPE_REVERT:
20392099
rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,

boot/mynewt/mcuboot_config/include/mcuboot_config/mcuboot_config.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@
8585
#if MYNEWT_VAL(BOOTUTIL_BOOTSTRAP)
8686
#define MCUBOOT_BOOTSTRAP 1
8787
#endif
88+
#if MYNEWT_VAL_CHOICE(BOOTUTIL_DOWNGRADE_PREVENTION, version)
89+
#define MCUBOOT_DOWNGRADE_PREVENTION 1
90+
/* MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER is used later as bool value so it is
91+
* always defined, (unlike MCUBOOT_DOWNGRADE_PREVENTION which is only used in
92+
* preprocessor condition and my be not defined) */
93+
#define MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER 0
94+
#elif MYNEWT_VAL_CHOICE(BOOTUTIL_DOWNGRADE_PREVENTION, security_counter)
95+
#define MCUBOOT_DOWNGRADE_PREVENTION 1
96+
#define MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER 1
97+
#endif
98+
#if MYNEWT_VAL(BOOTUTIL_HW_DOWNGRADE_PREVENTION)
99+
#define MCUBOOT_HW_ROLLBACK_PROT 1
100+
#endif
88101

89102
#if MYNEWT_VAL(MCUBOOT_MEASURED_BOOT)
90103
#define MCUBOOT_MEASURED_BOOT 1

boot/mynewt/mcuboot_config/syscfg.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,34 @@ syscfg.defs:
7676
BOOTUTIL_MAX_IMG_SECTORS:
7777
description: 'Maximum number of sectors that are swapped.'
7878
value: 128
79+
BOOTUTIL_DOWNGRADE_PREVENTION:
80+
description: >
81+
Select downgrade prevention strategy.
82+
- none downgrades are allowed
83+
- version:
84+
Prevent downgrades by enforcing incrementing version numbers.
85+
When this option is set, any upgrade must have greater major version
86+
or greater minor version with equal major version. This mechanism
87+
only protects against some attacks against version downgrades (for
88+
example, a JTAG could be used to write an older version).
89+
- security_counter:
90+
security counter is used for version eligibility check instead of pure
91+
version. When this option is set, any upgrade must have greater or
92+
equal security counter value.
93+
Because of the acceptance of equal values it allows for software
94+
downgrades to some extent.
95+
choices:
96+
- none
97+
- version
98+
- security_counter
99+
value: none
100+
BOOTUTIL_HW_ROLLBACK_PROT:
101+
description: >
102+
Prevent undesirable/malicious software downgrades. When this option is
103+
set, any upgrade must have greater or equal security counter value.
104+
Because of the acceptance of equal values it allows for software
105+
downgrade to some extent
106+
value: 0
79107
BOOTUTIL_HAVE_LOGGING:
80108
description: 'Enable serial logging'
81109
value: 0

0 commit comments

Comments
 (0)