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 */
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
8284static 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 */
9092static 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 ];
0 commit comments