Skip to content

Commit 4c95aa4

Browse files
mahavirjKonstantinKondrashov
authored andcommitted
fix(ota): additional checks for secure version in anti-rollback case
Some additional checks related to secure version of the application in anti-rollback case have been added to avoid any attempts to boot lower security version but valid application (e.g., passive partition image). - Read secure_version under sha256 protection - First check has been added in the bootloader to ensure correct secure version after application verification and loading stage. This check happens before setting up the flash cache mapping and handling over the final control to application. This check ensures that application was not swapped (e.g., to lower security version but valid image) just before the load stage in bootloader. - Second check has been added in the application startup code to ensure that currently booting app has higher security version than the one programmed in the eFuse for anti-rollback scenario. This will ensure that only the legit application boots-up on the device for anti-rollback case.
1 parent cc649ea commit 4c95aa4

File tree

5 files changed

+77
-8
lines changed

5 files changed

+77
-8
lines changed

components/bootloader_support/include/esp_image_format.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ typedef struct {
3333
uint32_t segment_data[ESP_IMAGE_MAX_SEGMENTS]; /* Data offsets for each segment */
3434
uint32_t image_len; /* Length of image on flash, in bytes */
3535
uint8_t image_digest[32]; /* appended SHA-256 digest */
36+
uint32_t secure_version; /* secure version for anti-rollback, it is covered by sha256 (set if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK=y) */
3637
} esp_image_metadata_t;
3738

3839
typedef enum {

components/bootloader_support/src/esp_image_format.c

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -19,6 +19,8 @@
1919
#include "bootloader_util.h"
2020
#include "bootloader_common.h"
2121
#include "esp_rom_sys.h"
22+
#include "esp_efuse.h"
23+
#include "esp_app_desc.h"
2224
#include "bootloader_memory_utils.h"
2325
#include "soc/soc_caps.h"
2426
#include "hal/cache_ll.h"
@@ -89,10 +91,10 @@ static bool should_map(uint32_t load_addr);
8991

9092
static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum);
9193
/* Load or verify a segment */
92-
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum);
94+
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata);
9395

9496
/* split segment and verify if data_len is too long */
95-
static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum);
97+
static esp_err_t process_segment_data(int segment, intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata);
9698

9799
/* Verify the main image header */
98100
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent);
@@ -240,6 +242,21 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
240242
cache_ll_writeback_all(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);
241243
#endif
242244
}
245+
246+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
247+
/* For anti-rollback case, reconfirm security version of the application to prevent FI attacks */
248+
bool sec_ver = false;
249+
if (do_load) {
250+
sec_ver = esp_efuse_check_secure_version(data->secure_version);
251+
if (!sec_ver) {
252+
err = ESP_FAIL;
253+
goto err;
254+
}
255+
}
256+
/* Ensure that the security version check passes for image loading scenario */
257+
ESP_FAULT_ASSERT(!do_load || sec_ver == true);
258+
#endif // CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
259+
243260
#endif // BOOTLOADER_BUILD
244261

245262
// Success!
@@ -522,7 +539,7 @@ static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool
522539
for (int i = 0; i < data->image.segment_count; i++) {
523540
esp_image_segment_header_t *header = &data->segments[i];
524541
ESP_LOGV(TAG, "loading segment header %d at offset 0x%"PRIx32, i, next_addr);
525-
CHECK_ERR(process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum));
542+
CHECK_ERR(process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum, data));
526543
next_addr += sizeof(esp_image_segment_header_t);
527544
data->segment_data[i] = next_addr;
528545
next_addr += header->data_len;
@@ -543,7 +560,7 @@ static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool
543560
return err;
544561
}
545562

546-
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
563+
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata)
547564
{
548565
esp_err_t err;
549566

@@ -601,7 +618,7 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
601618
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
602619
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
603620
data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
604-
CHECK_ERR(process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum));
621+
CHECK_ERR(process_segment_data(index, load_addr, data_addr, data_len, do_load, sha_handle, checksum, metadata));
605622
data_addr += data_len;
606623
data_len_remain -= data_len;
607624
}
@@ -616,7 +633,42 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
616633
return err;
617634
}
618635

619-
static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
636+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
637+
/* The __attribute__((optimize("O0"))) is used to disable optimizations for this function,
638+
* preventing the compiler from potentially optimizing data_buffer and reading data directly from src.
639+
* This is crucial as we want to read from Flash only once, ensuring the integrity of the data.
640+
*/
641+
__attribute__((optimize("O0")))
642+
static size_t process_esp_app_desc_data(const uint32_t *src, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata)
643+
{
644+
/* Using data_buffer here helps to securely read secure_version
645+
* (for anti-rollback) from esp_app_desc_t, preventing FI attack.
646+
* We read data from Flash into this buffer, which is covered by sha256.
647+
* Therefore, if the flash is under attackers control and contents are modified
648+
* the sha256 comparison will fail.
649+
*
650+
* The esp_app_desc_t structure is located in DROM and is always in segment #0.
651+
*
652+
* esp_app_desc_t is always at #0 segment (index==0).
653+
* secure_version field of esp_app_desc_t is located at #2 word (w_i==1).
654+
*/
655+
uint32_t data_buffer[2];
656+
memcpy(data_buffer, src, sizeof(data_buffer));
657+
assert(data_buffer[0] == ESP_APP_DESC_MAGIC_WORD);
658+
metadata->secure_version = data_buffer[1];
659+
if (checksum != NULL) {
660+
*checksum ^= data_buffer[0] ^ data_buffer[1];
661+
}
662+
if (sha_handle != NULL) {
663+
bootloader_sha256_data(sha_handle, data_buffer, sizeof(data_buffer));
664+
}
665+
ESP_FAULT_ASSERT(memcmp(data_buffer, src, sizeof(data_buffer)) == 0);
666+
ESP_FAULT_ASSERT(memcmp(&metadata->secure_version, &src[1], sizeof(uint32_t)) == 0);
667+
return sizeof(data_buffer);
668+
}
669+
#endif // CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
670+
671+
static esp_err_t process_segment_data(int segment, intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata)
620672
{
621673
// If we are not loading, and the checksum is empty, skip processing this
622674
// segment for data
@@ -653,6 +705,16 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui
653705

654706
const uint32_t *src = data;
655707

708+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
709+
if (segment == 0) {
710+
// The esp_app_desc_t structure is located in DROM and is always in segment #0.
711+
size_t len = process_esp_app_desc_data(src, sha_handle, checksum, metadata);
712+
data_len -= len;
713+
src += len / 4;
714+
// In BOOTLOADER_BUILD, for DROM (segment #0) we do not load it into dest (only map it), do_load = false.
715+
}
716+
#endif // CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
717+
656718
for (size_t i = 0; i < data_len; i += 4) {
657719
int w_i = i / 4; // Word index
658720
uint32_t w = src[w_i];

components/esp_app_format/include/esp_app_desc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef struct {
3838

3939
/** @cond */
4040
ESP_STATIC_ASSERT(sizeof(esp_app_desc_t) == 256, "esp_app_desc_t should be 256 bytes");
41+
ESP_STATIC_ASSERT(offsetof(esp_app_desc_t, secure_version) == 4, "secure_version field must be at 4 offset");
4142
/** @endcond */
4243

4344
/**

components/esp_system/startup.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ static void do_core_init(void)
340340
#endif
341341
#endif
342342

343+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
344+
// For anti-rollback case, recheck security version before we boot-up the current application
345+
assert(esp_efuse_check_secure_version(esp_app_get_description()->secure_version) == true && "Incorrect secure version of app");
346+
#endif
347+
343348
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
344349
esp_flash_encryption_init_checks();
345350
#endif

tools/test_apps/system/bootloader_sections/sdkconfig.ci.anti_rollback

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK=y
33
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
44
CONFIG_PARTITION_TABLE_CUSTOM=y
55
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
6-
CONFIG_PARTITION_TABLE_OFFSET=0x9000
6+
CONFIG_PARTITION_TABLE_OFFSET=0xA000

0 commit comments

Comments
 (0)