mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
bootloader: Obfuscate loaded memory until verification is complete
This commit is contained in:
parent
0c8888d68f
commit
8f6134dd96
@ -18,6 +18,7 @@
|
||||
#include <esp_image_format.h>
|
||||
#include <esp_log.h>
|
||||
#include <bootloader_flash.h>
|
||||
#include <bootloader_random.h>
|
||||
|
||||
static const char *TAG = "esp_image";
|
||||
|
||||
@ -27,6 +28,13 @@ static const char *TAG = "esp_image";
|
||||
/* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */
|
||||
#define STACK_LOAD_HEADROOM 4096
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
/* 64 bits of random data to obfuscate loaded RAM with, until verification is complete
|
||||
(Means loaded code isn't executable until after the secure boot check.)
|
||||
*/
|
||||
static uint32_t ram_obfs_value[2];
|
||||
#endif
|
||||
|
||||
/* Return true if load_addr is an address the bootloader should load into */
|
||||
static bool should_load(uint32_t load_addr);
|
||||
/* Return true if load_addr is an address the bootloader should map via flash cache */
|
||||
@ -98,7 +106,7 @@ goto err;
|
||||
}
|
||||
|
||||
uint32_t next_addr = data->start_addr + sizeof(esp_image_header_t);
|
||||
for(int i = 0; i < data->image.segment_count && err == ESP_OK; i++) {
|
||||
for(int i = 0; i < data->image.segment_count; i++) {
|
||||
esp_image_segment_header_t *header = &data->segments[i];
|
||||
ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
|
||||
err = process_segment(i, next_addr, header, silent, do_load, &checksum_word);
|
||||
@ -138,6 +146,20 @@ goto err;
|
||||
|
||||
data->image_length = length;
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
if (do_load) { // Need to deobfuscate RAM
|
||||
for (int i = 0; i < data->image.segment_count; i++) {
|
||||
uint32_t load_addr = data->segments[i].load_addr;
|
||||
if (should_load(load_addr)) {
|
||||
uint32_t *loaded = (uint32_t *)load_addr;
|
||||
for (int j = 0; j < data->segments[i].data_len/sizeof(uint32_t); j++) {
|
||||
loaded[j] ^= (j & 1) ? ram_obfs_value[0] : ram_obfs_value[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Success!
|
||||
return ESP_OK;
|
||||
|
||||
@ -222,24 +244,31 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
}
|
||||
}
|
||||
|
||||
const void *data = bootloader_mmap(data_addr, data_len);
|
||||
const uint32_t *data = (const uint32_t *)bootloader_mmap(data_addr, data_len);
|
||||
if(!data) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed",
|
||||
data_addr, data_len);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
const uint32_t *checksum_from;
|
||||
if (do_load) {
|
||||
memcpy((void *)load_addr, data, data_len);
|
||||
checksum_from = (const uint32_t *)load_addr;
|
||||
} else {
|
||||
checksum_from = (const uint32_t *)data;
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
// Set up the obfuscation value to use for loading
|
||||
while (ram_obfs_value[0] == 0 || ram_obfs_value[1] == 0) {
|
||||
bootloader_fill_random(ram_obfs_value, sizeof(ram_obfs_value));
|
||||
}
|
||||
// Update checksum, either from RAM we just loaded or from flash
|
||||
for (const uint32_t *c = checksum_from;
|
||||
c < checksum_from + (data_len/sizeof(uint32_t));
|
||||
c++) {
|
||||
*checksum ^= *c;
|
||||
uint32_t *dest = (uint32_t *)load_addr;
|
||||
#endif
|
||||
|
||||
const uint32_t *src = data;
|
||||
|
||||
for (int i = 0; i < data_len/sizeof(uint32_t); i++) {
|
||||
uint32_t w = src[i];
|
||||
*checksum ^= w;
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
if (do_load) {
|
||||
dest[i] = w ^ ((i & 1) ? ram_obfs_value[0] : ram_obfs_value[1]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bootloader_munmap(data);
|
||||
@ -264,13 +293,14 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
||||
}
|
||||
|
||||
uint32_t load_addr = segment->load_addr;
|
||||
bool map_segment = should_map(load_addr);
|
||||
|
||||
/* Check that flash cache mapped segment aligns correctly from flash to its mapped address,
|
||||
relative to the 64KB page mapping size.
|
||||
*/
|
||||
ESP_LOGV(TAG, "segment %d map_segment %d segment_data_offs 0x%x load_addr 0x%x",
|
||||
index, map_segment, segment_data_offs, load_addr);
|
||||
if (should_map(load_addr)
|
||||
if (map_segment
|
||||
&& ((segment_data_offs % SPI_FLASH_MMU_PAGE_SIZE) != (load_addr % SPI_FLASH_MMU_PAGE_SIZE))) {
|
||||
if (!silent) {
|
||||
ESP_LOGE(TAG, "Segment %d has load address 0x%08x, doesn't match segment data at 0x%08x",
|
||||
|
Loading…
Reference in New Issue
Block a user