dfu: img_util: Add flash integrity check

Flash memory can be write but there is no way to check flash integrity.
Add flash_img_check method that verify flash integrity.  This is useful
to avoid firmware reboot and test.  Another use is ensure that firmware
upgrade routines from internet server to flash slot are performing
properly.  This uses flash_area_check_int_sha256 method to check a
SHA-256 hash.  On sucess match, zero is returned, otherwise a negative
errno value.

Signed-off-by: Gerson Fernando Budke <nandojve@gmail.com>
This commit is contained in:
Gerson Fernando Budke 2020-07-09 23:57:32 -03:00 committed by Carles Cufí
commit 4d35d3d83a
7 changed files with 131 additions and 1 deletions

View file

@ -20,6 +20,19 @@ struct flash_img_context {
struct stream_flash_ctx stream;
};
#if defined(CONFIG_IMG_ENABLE_IMAGE_CHECK)
/**
* @brief Structure for verify flash region integrity
*
* Match vector length is fixed and depends on size from hash algorithm used
* to verify flash integrity. The current available algorithm is SHA-256.
*/
struct flash_img_check {
const uint8_t *match; /** Match vector data */
size_t clen; /** Content to be compared */
};
#endif
/**
* @brief Initialize context needed for writing the image to the flash.
*
@ -68,6 +81,23 @@ size_t flash_img_bytes_written(struct flash_img_context *ctx);
int flash_img_buffered_write(struct flash_img_context *ctx, const uint8_t *data,
size_t len, bool flush);
#if defined(CONFIG_IMG_ENABLE_IMAGE_CHECK)
/**
* @brief Verify flash memory length bytes integrity from a flash area. The
* start point is indicated by an offset value.
*
* @param[in] ctx context.
* @param[in] fic flash img check data.
* @param[in] area_id flash area id of partition where the image should be
* verified.
*
* @return 0 on success, negative errno code on fail
*/
int flash_img_check(struct flash_img_context *ctx,
const struct flash_img_check *fic,
uint8_t area_id);
#endif
#ifdef __cplusplus
}
#endif

View file

@ -59,6 +59,17 @@ config IMG_ERASE_PROGRESSIVELY
on some hardware that has long erase times, to prevent long wait
times at the beginning of the DFU process.
config IMG_ENABLE_IMAGE_CHECK
bool "Enable image check functions"
depends on MCUBOOT_IMG_MANAGER
select FLASH_AREA_CHECK_INTEGRITY
help
If enabled, there will be available the function to check flash
integrity. It can be used to verify flash integrity after received
a new firmware. This is useful to avoid firmware reboot and test.
Another use is to ensure that firmware upgrade routines from internet
server to flash slot are performing properly.
module = IMG_MANAGER
module-str = image manager
source "subsys/logging/Kconfig.template.log_config"

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2017, 2020 Nordic Semiconductor ASA
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -83,3 +84,36 @@ int flash_img_init(struct flash_img_context *ctx)
{
return flash_img_init_id(ctx, FLASH_AREA_IMAGE_SECONDARY);
}
#if defined(CONFIG_IMG_ENABLE_IMAGE_CHECK)
int flash_img_check(struct flash_img_context *ctx,
const struct flash_img_check *fic,
uint8_t area_id)
{
struct flash_area_check fac;
int rc;
if (!ctx || !fic) {
return -EINVAL;
}
rc = flash_area_open(area_id,
(const struct flash_area **)&(ctx->flash_area));
if (rc) {
return rc;
}
fac.match = fic->match;
fac.clen = fic->clen;
fac.off = 0;
fac.rbuf = ctx->buf;
fac.rblen = sizeof(ctx->buf);
rc = flash_area_check_int_sha256(ctx->flash_area, &fac);
flash_area_close(ctx->flash_area);
ctx->flash_area = NULL;
return rc;
}
#endif

View file

@ -2,6 +2,7 @@ CONFIG_ZTEST=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_FLASH=y
CONFIG_IMG_MANAGER=y
CONFIG_IMG_ENABLE_IMAGE_CHECK=y
CONFIG_MCUBOOT_IMG_MANAGER=y
CONFIG_IMG_BLOCK_BUF_SIZE=512
CONFIG_ARM_MPU=n

View file

@ -2,5 +2,6 @@ CONFIG_ZTEST=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_FLASH=y
CONFIG_IMG_MANAGER=y
CONFIG_IMG_ENABLE_IMAGE_CHECK=y
CONFIG_MCUBOOT_IMG_MANAGER=y
CONFIG_IMG_BLOCK_BUF_SIZE=512

View file

@ -2,5 +2,6 @@ CONFIG_ZTEST=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_FLASH=y
CONFIG_IMG_MANAGER=y
CONFIG_IMG_ENABLE_IMAGE_CHECK=y
CONFIG_MCUBOOT_IMG_MANAGER=y
CONFIG_IMG_BLOCK_BUF_SIZE=512

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -107,11 +108,62 @@ void test_collecting(void)
#endif
}
void test_check_flash(void)
{
/* echo $'0123456789abcdef\nfedcba9876543201' > tst.sha
* hexdump tst.sha
*/
uint8_t tst_vec[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x0a, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x39,
0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
0x30, 0x0a };
/* sha256sum tst.sha */
uint8_t tst_sha[] = { 0xc6, 0xb6, 0x7c, 0x46, 0xe7, 0x2e, 0x14, 0x17,
0x49, 0xa4, 0xd2, 0xf1, 0x38, 0x58, 0xb2, 0xa7,
0x54, 0xaf, 0x6d, 0x39, 0x50, 0x6b, 0xd5, 0x41,
0x90, 0xf6, 0x18, 0x1a, 0xe0, 0xc2, 0x7f, 0x98 };
struct flash_img_check fic = { NULL, 0 };
struct flash_img_context ctx;
int ret;
ret = flash_img_init_id(&ctx, FLASH_AREA_ID(image_1));
zassert_true(ret == 0, "Flash img init 1");
ret = flash_area_erase(ctx.flash_area, 0, ctx.flash_area->fa_size);
zassert_true(ret == 0, "Flash erase failure (%d)\n", ret);
ret = flash_img_buffered_write(&ctx, tst_vec, sizeof(tst_vec), true);
zassert_true(ret == 0, "Flash img buffered write\n");
ret = flash_img_check(NULL, NULL, 0);
zassert_true(ret == -EINVAL, "Flash img check params 1, 2\n");
ret = flash_img_check(NULL, &fic, 0);
zassert_true(ret == -EINVAL, "Flash img check params 2\n");
ret = flash_img_check(&ctx, NULL, 0);
zassert_true(ret == -EINVAL, "Flash img check params 1\n");
ret = flash_img_check(&ctx, &fic, FLASH_AREA_ID(image_1));
zassert_true(ret == -EINVAL, "Flash img check fic match\n");
fic.match = tst_sha;
ret = flash_img_check(&ctx, &fic, FLASH_AREA_ID(image_1));
zassert_true(ret == -EINVAL, "Flash img check fic len\n");
fic.clen = sizeof(tst_vec);
ret = flash_img_check(&ctx, &fic, FLASH_AREA_ID(image_1));
zassert_true(ret == 0, "Flash img check\n");
tst_sha[0] = 0x00;
ret = flash_img_check(&ctx, &fic, FLASH_AREA_ID(image_1));
zassert_false(ret == 0, "Flash img check wrong sha\n");
flash_area_close(ctx.flash_area);
}
void test_main(void)
{
ztest_test_suite(test_util,
ztest_unit_test(test_collecting),
ztest_unit_test(test_init_id)
ztest_unit_test(test_init_id),
ztest_unit_test(test_check_flash)
);
ztest_run_test_suite(test_util);
}