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>
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 24dcab4..e59fad7 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -616,7 +616,7 @@
#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 @@
#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 @@
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,