1
1
/*
2
- * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
2
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
3
3
*
4
4
* SPDX-License-Identifier: Apache-2.0
5
5
*/
19
19
#include "bootloader_util.h"
20
20
#include "bootloader_common.h"
21
21
#include "esp_rom_sys.h"
22
+ #include "esp_efuse.h"
23
+ #include "esp_app_desc.h"
22
24
#include "bootloader_memory_utils.h"
23
25
#include "soc/soc_caps.h"
24
26
#if CONFIG_IDF_TARGET_ESP32
@@ -81,10 +83,10 @@ static bool should_map(uint32_t load_addr);
81
83
82
84
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 );
83
85
/* 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 );
85
87
86
88
/* 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 );
88
90
89
91
/* Verify the main image header */
90
92
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_
229
231
}
230
232
}
231
233
}
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
+
232
249
#endif // BOOTLOADER_BUILD
233
250
234
251
// Success!
@@ -504,8 +521,8 @@ static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool
504
521
uint32_t next_addr = start_segments ;
505
522
for (int i = 0 ; i < data -> image .segment_count ; i ++ ) {
506
523
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 ));
509
526
next_addr += sizeof (esp_image_segment_header_t );
510
527
data -> segment_data [i ] = next_addr ;
511
528
next_addr += header -> data_len ;
@@ -526,7 +543,7 @@ static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool
526
543
return err ;
527
544
}
528
545
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 )
530
547
{
531
548
esp_err_t err ;
532
549
@@ -584,7 +601,7 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
584
601
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK ) != 0 ) ? 1 : 0 ;
585
602
/* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
586
603
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 ));
588
605
data_addr += data_len ;
589
606
data_len_remain -= data_len ;
590
607
}
@@ -599,7 +616,42 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
599
616
return err ;
600
617
}
601
618
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 )
603
655
{
604
656
// If we are not loading, and the checksum is empty, skip processing this
605
657
// segment for data
@@ -632,10 +684,24 @@ static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, ui
632
684
#endif
633
685
}
634
686
uint32_t * dest = (uint32_t * )load_addr ;
635
- #endif
687
+ #endif // BOOTLOADER_BUILD
636
688
637
689
const uint32_t * src = data ;
638
690
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
+
639
705
for (size_t i = 0 ; i < data_len ; i += 4 ) {
640
706
int w_i = i / 4 ; // Word index
641
707
uint32_t w = src [w_i ];
0 commit comments