Commit e3f895d7 authored by Jerzy Kasenberg's avatar Jerzy Kasenberg Committed by David Brown
Browse files

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: default avatarJerzy Kasenberg <jerzy.kasenberg@codecoup.pl>
parent 4e2cdfe8
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -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.
+62 −2
Original line number Diff line number Diff line
@@ -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,
+13 −0
Original line number Diff line number Diff line
@@ -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
+28 −0
Original line number Diff line number Diff line
@@ -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