Skip to content

Commit 534e3ad

Browse files
committed
Merge branch 'bugfix/ota_anti_rollback_checks_2_v5.0' into 'release/v5.0'
feat(bootloader_support): Read secure_version under sha256 protection (v5.0) See merge request espressif/esp-idf!29061
2 parents 96e3e4c + 1620858 commit 534e3ad

File tree

5 files changed

+83
-10
lines changed

5 files changed

+83
-10
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: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2022 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
#if CONFIG_IDF_TARGET_ESP32
@@ -81,10 +83,10 @@ static bool should_map(uint32_t load_addr);
8183

8284
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);
8385
/* Load or verify a segment */
84-
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);
86+
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);
8587

8688
/* split segment and verify if data_len is too long */
87-
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);
89+
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);
8890

8991
/* Verify the main image header */
9092
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent);
@@ -229,6 +231,21 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_
229231
}
230232
}
231233
}
234+
235+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
236+
/* For anti-rollback case, reconfirm security version of the application to prevent FI attacks */
237+
bool sec_ver = false;
238+
if (do_load) {
239+
sec_ver = esp_efuse_check_secure_version(data->secure_version);
240+
if (!sec_ver) {
241+
err = ESP_FAIL;
242+
goto err;
243+
}
244+
}
245+
/* Ensure that the security version check passes for image loading scenario */
246+
ESP_FAULT_ASSERT(!do_load || sec_ver == true);
247+
#endif // CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
248+
232249
#endif // BOOTLOADER_BUILD
233250

234251
// Success!
@@ -504,8 +521,8 @@ static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool
504521
uint32_t next_addr = start_segments;
505522
for (int i = 0; i < data->image.segment_count; i++) {
506523
esp_image_segment_header_t *header = &data->segments[i];
507-
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
508-
CHECK_ERR(process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum));
524+
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, data));
509526
next_addr += sizeof(esp_image_segment_header_t);
510527
data->segment_data[i] = next_addr;
511528
next_addr += header->data_len;
@@ -526,7 +543,7 @@ static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool
526543
return err;
527544
}
528545

529-
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)
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, esp_image_metadata_t *metadata)
530547
{
531548
esp_err_t err;
532549

@@ -584,7 +601,7 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
584601
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
585602
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
586603
data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
587-
CHECK_ERR(process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum));
604+
CHECK_ERR(process_segment_data(index, load_addr, data_addr, data_len, do_load, sha_handle, checksum, metadata));
588605
data_addr += data_len;
589606
data_len_remain -= data_len;
590607
}
@@ -599,7 +616,42 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
599616
return err;
600617
}
601618

602-
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)
619+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
620+
/* The __attribute__((optimize("O0"))) is used to disable optimizations for this function,
621+
* preventing the compiler from potentially optimizing data_buffer and reading data directly from src.
622+
* This is crucial as we want to read from Flash only once, ensuring the integrity of the data.
623+
*/
624+
__attribute__((optimize("O0")))
625+
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)
626+
{
627+
/* Using data_buffer here helps to securely read secure_version
628+
* (for anti-rollback) from esp_app_desc_t, preventing FI attack.
629+
* We read data from Flash into this buffer, which is covered by sha256.
630+
* Therefore, if the flash is under attackers control and contents are modified
631+
* the sha256 comparison will fail.
632+
*
633+
* The esp_app_desc_t structure is located in DROM and is always in segment #0.
634+
*
635+
* esp_app_desc_t is always at #0 segment (index==0).
636+
* secure_version field of esp_app_desc_t is located at #2 word (w_i==1).
637+
*/
638+
uint32_t data_buffer[2];
639+
memcpy(data_buffer, src, sizeof(data_buffer));
640+
assert(data_buffer[0] == ESP_APP_DESC_MAGIC_WORD);
641+
metadata->secure_version = data_buffer[1];
642+
if (checksum != NULL) {
643+
*checksum ^= data_buffer[0] ^ data_buffer[1];
644+
}
645+
if (sha_handle != NULL) {
646+
bootloader_sha256_data(sha_handle, data_buffer, sizeof(data_buffer));
647+
}
648+
ESP_FAULT_ASSERT(memcmp(data_buffer, src, sizeof(data_buffer)) == 0);
649+
ESP_FAULT_ASSERT(memcmp(&metadata->secure_version, &src[1], sizeof(uint32_t)) == 0);
650+
return sizeof(data_buffer);
651+
}
652+
#endif // CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
653+
654+
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)
603655
{
604656
// If we are not loading, and the checksum is empty, skip processing this
605657
// segment for data
@@ -632,10 +684,24 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui
632684
#endif
633685
}
634686
uint32_t *dest = (uint32_t *)load_addr;
635-
#endif
687+
#endif // BOOTLOADER_BUILD
636688

637689
const uint32_t *src = data;
638690

691+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
692+
// Case I: Bootloader verifying application
693+
// Case II: Bootloader verifying bootloader
694+
// Anti-rollback check should handle only Case I from above.
695+
if (segment == 0 && metadata->start_addr != ESP_BOOTLOADER_OFFSET) {
696+
ESP_LOGD(TAG, "additional anti-rollback check 0x%"PRIx32, data_addr);
697+
// The esp_app_desc_t structure is located in DROM and is always in segment #0.
698+
size_t len = process_esp_app_desc_data(src, sha_handle, checksum, metadata);
699+
data_len -= len;
700+
src += len / 4;
701+
// In BOOTLOADER_BUILD, for DROM (segment #0) we do not load it into dest (only map it), do_load = false.
702+
}
703+
#endif // CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
704+
639705
for (size_t i = 0; i < data_len; i += 4) {
640706
int w_i = i / 4; // Word index
641707
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
@@ -37,6 +37,7 @@ typedef struct {
3737

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

4243
/**

components/esp_system/startup.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,11 @@ static void do_core_init(void)
353353
#endif
354354
#endif
355355

356+
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
357+
// For anti-rollback case, recheck security version before we boot-up the current application
358+
assert(esp_efuse_check_secure_version(esp_app_get_description()->secure_version) == true && "Incorrect secure version of app");
359+
#endif
360+
356361
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
357362
esp_flash_encryption_init_checks();
358363
#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)