From 61f392a4bb4b844e82fd89ce6db0edf8dbf979f2 Mon Sep 17 00:00:00 2001 From: Mateo Ligne Date: Mon, 13 Dec 2021 14:14:59 +0100 Subject: [PATCH] boot_serial: Software downgrade prevention in serial recovery configuration Signed-off-by: mateo-ligne-netatmo --- boot/boot_serial/src/boot_serial.c | 41 +++++++++++++++++++++++ boot/boot_serial/src/boot_serial_priv.h | 1 + boot/zephyr/Kconfig | 2 +- boot/zephyr/include/single_loader.h | 16 +++++++++ boot/zephyr/single_loader.c | 43 +++++++++++++++++++++++-- 5 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 boot/zephyr/include/single_loader.h diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 69551e57b8..6dde2a5fdb 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -58,6 +58,10 @@ #include "bootutil_priv.h" #endif +#ifdef MCUBOOT_DOWNGRADE_PREVENTION +#include "single_loader.h" +#endif + #include "serial_recovery_cbor.h" #include "bootutil/boot_hooks.h" @@ -102,6 +106,9 @@ static cbor_state_backups_t dummy_backups; static cbor_state_t cbor_state = { .backups = &dummy_backups }; +#ifdef MCUBOOT_DOWNGRADE_PREVENTION +static bool updatable; +#endif /*MCUBOOT_DOWNGRADE_PREVENTION*/ /** * Function that processes MGMT_GROUP_ID_PERUSER mcumgr group and may be @@ -255,6 +262,10 @@ bs_upload(char *buf, int len) static off_t off_last = -1; struct flash_sector sector; #endif +#ifdef MCUBOOT_DOWNGRADE_PREVENTION + struct image_header* inc_hdr = NULL; + struct image_header st_hdr; +#endif /*MCUBOOT_DOWNGRADE_PREVENTION*/ img_num = 0; @@ -317,6 +328,36 @@ bs_upload(char *buf, int len) goto out; } +#ifdef MCUBOOT_DOWNGRADE_PREVENTION + /* Comparison should happen once, on the reception of header */ + if (off == 0) + { + inc_hdr = (struct image_header*)img_data; + rc = BOOT_HOOK_CALL(boot_read_image_header_hook, + BOOT_HOOK_REGULAR, 0, 0, &st_hdr); + if (rc == BOOT_HOOK_REGULAR) + { + flash_area_read(fap, 0, &st_hdr, sizeof(st_hdr)); + } + updatable = true; + /* Check if a firmware is already stored, if yes, compare versions */ + if (st_hdr.ih_img_size < flash_area_get_size(fap)) + { + rc = boot_version_cmp(&st_hdr.ih_ver, + &inc_hdr->ih_ver); + if (rc > 0) { + BOOT_LOG_INF("Update aborted due to strictly lower firmware version"); + updatable = false; + } + } + } + if (!updatable) + { + rc = MGMT_ERR_REJECTED_UPD; + goto out; + } +#endif /*MCUBOOT_DOWNGRADE_PREVENTION*/ + if (off == 0) { curr_off = 0; if (data_len > flash_area_get_size(fap)) { diff --git a/boot/boot_serial/src/boot_serial_priv.h b/boot/boot_serial/src/boot_serial_priv.h index 5e0211c0d6..fb3d85e9b8 100644 --- a/boot/boot_serial/src/boot_serial_priv.h +++ b/boot/boot_serial/src/boot_serial_priv.h @@ -40,6 +40,7 @@ extern "C" { #define MGMT_ERR_EUNKNOWN 2 #define MGMT_ERR_EINVAL 3 #define MGMT_ERR_ENOTSUP 8 +#define MGMT_ERR_REJECTED_UPD 10 #define NMGR_OP_READ 0 #define NMGR_OP_WRITE 2 diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 5d71cd25ae..ad54f3c92e 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -600,7 +600,7 @@ choice config MCUBOOT_DOWNGRADE_PREVENTION bool "SW based downgrade prevention" - depends on BOOT_UPGRADE_ONLY + depends on BOOT_UPGRADE_ONLY || MCUBOOT_SERIAL help Prevent downgrades by enforcing incrementing version numbers. When this option is set, any upgrade must have greater major version diff --git a/boot/zephyr/include/single_loader.h b/boot/zephyr/include/single_loader.h new file mode 100644 index 0000000000..1b747d605c --- /dev/null +++ b/boot/zephyr/include/single_loader.h @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2021-2021 Crodeon Technologies + * + */ + +#ifndef H_SINGLE_LOADER_ +#define H_SINGLE_LOADER_ + +int boot_image_load_header(const struct flash_area *fa_p, + struct image_header *hdr); + +int boot_version_cmp(const struct image_version *ver1, + const struct image_version *ver2); +#endif diff --git a/boot/zephyr/single_loader.c b/boot/zephyr/single_loader.c index af2d398d6c..feeee3cb3a 100644 --- a/boot/zephyr/single_loader.c +++ b/boot/zephyr/single_loader.c @@ -48,7 +48,6 @@ boot_image_validate(const struct flash_area *fa_p, } #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */ - /** * Attempts to load image header from flash; verifies flash header fields. * @@ -57,7 +56,7 @@ boot_image_validate(const struct flash_area *fa_p, * * @return 0 on success, error code otherwise */ -static int +int boot_image_load_header(const struct flash_area *fa_p, struct image_header *hdr) { @@ -90,6 +89,46 @@ boot_image_load_header(const struct flash_area *fa_p, return 0; } +#ifdef MCUBOOT_DOWNGRADE_PREVENTION +/** + * Compare image version numbers not including the build number + * + * @param ver1 Pointer to the first image version to compare. + * @param ver2 Pointer to the second image version to compare. + * + * @retval -1 If ver1 is strictly less than ver2. + * @retval 0 If the image version numbers are equal, + * (not including the build number). + * @retval 1 If ver1 is strictly greater than ver2. + */ +int +boot_version_cmp(const struct image_version *ver1, + const struct image_version *ver2) +{ + if (ver1->iv_major > ver2->iv_major) { + return 1; + } + if (ver1->iv_major < ver2->iv_major) { + return -1; + } + /* The major version numbers are equal, continue comparison. */ + if (ver1->iv_minor > ver2->iv_minor) { + return 1; + } + if (ver1->iv_minor < ver2->iv_minor) { + return -1; + } + /* The minor version numbers are equal, continue comparison. */ + if (ver1->iv_revision > ver2->iv_revision) { + return 1; + } + if (ver1->iv_revision < ver2->iv_revision) { + return -1; + } + + return 0; +} +#endif /*MCUBOOT_DOWNGRADE_PREVENTION*/ /** * Gather information on image and prepare for booting.