Skip to content

Commit bb56d86

Browse files
committed
Merge branch 'bugfix/bootloader_iram_overlap_check_v3.0' into 'release/v3.0'
bootloader: verify that loaded image does not overlap bootloader code (backport v3.0) See merge request idf/esp-idf!3527
2 parents 099ae5a + db22238 commit bb56d86

File tree

4 files changed

+89
-6
lines changed

4 files changed

+89
-6
lines changed

components/bootloader/subproject/main/esp32.bootloader.ld

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ SECTIONS
2727
.iram1.text :
2828
{
2929
. = ALIGN (16);
30+
_loader_text_start = ABSOLUTE(.);
3031
*(.entry.text)
3132
*(.init.literal)
3233
*(.init)
@@ -126,6 +127,7 @@ SECTIONS
126127
*(.fini)
127128
*(.gnu.version)
128129
_text_end = ABSOLUTE(.);
130+
_loader_text_end = ABSOLUTE(.);
129131
_etext = .;
130132
} > iram_seg
131133

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
#include <stddef.h>
18+
19+
/**
20+
* @brief Check if half-open intervals overlap
21+
*
22+
* @param start1 interval 1 start
23+
* @param end1 interval 1 end
24+
* @param start2 interval 2 start
25+
* @param end2 interval 2 end
26+
* @return true iff [start1; end1) overlaps [start2; end2)
27+
*/
28+
static inline bool bootloader_util_regions_overlap(
29+
const intptr_t start1, const intptr_t end1,
30+
const intptr_t start2, const intptr_t end2)
31+
{
32+
return (end1 > start2 && end2 > start1) ||
33+
!(end1 <= start2 || end2 <= start1);
34+
}

components/bootloader_support/src/esp_image_format.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <bootloader_flash.h>
2424
#include <bootloader_random.h>
2525
#include <bootloader_sha.h>
26+
#include "bootloader_util.h"
2627

2728
static const char *TAG = "esp_image";
2829

@@ -42,6 +43,10 @@ static const char *TAG = "esp_image";
4243
(Means loaded code isn't executable until after the secure boot check.)
4344
*/
4445
static uint32_t ram_obfs_value[2];
46+
47+
/* Range of IRAM used by the loader, defined in ld script */
48+
extern int _loader_text_start;
49+
extern int _loader_text_end;
4550
#endif
4651

4752
/* Return true if load_addr is an address the bootloader should load into */
@@ -286,18 +291,41 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
286291
(do_load)?"load":(is_mapping)?"map":"");
287292
}
288293

294+
295+
#ifdef BOOTLOADER_BUILD
296+
/* Before loading segment, check it doesn't clobber bootloader RAM. */
289297
if (do_load) {
290-
/* Before loading segment, check it doesn't clobber bootloader RAM... */
291-
uint32_t end_addr = load_addr + data_len;
292-
if (end_addr < 0x40000000) {
298+
const intptr_t load_end = load_addr + data_len;
299+
if (load_end <= (intptr_t) SOC_DIRAM_DRAM_HIGH) {
300+
/* Writing to DRAM */
293301
intptr_t sp = (intptr_t)get_sp();
294-
if (end_addr > sp - STACK_LOAD_HEADROOM) {
295-
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x liimit 0x%08x)",
296-
index, end_addr, sp, sp - STACK_LOAD_HEADROOM);
302+
if (load_end > sp - STACK_LOAD_HEADROOM) {
303+
/* Bootloader .data/.rodata/.bss is above the stack, so this
304+
* also checks that we aren't overwriting these segments.
305+
*
306+
* TODO: This assumes specific arrangement of sections we have
307+
* in the ESP32. Rewrite this in a generic way to support other
308+
* layouts.
309+
*/
310+
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x limit 0x%08x)",
311+
index, load_end, sp, sp - STACK_LOAD_HEADROOM);
312+
return ESP_ERR_IMAGE_INVALID;
313+
}
314+
} else {
315+
/* Writing to IRAM */
316+
const intptr_t loader_iram_start = (intptr_t) &_loader_text_start;
317+
const intptr_t loader_iram_end = (intptr_t) &_loader_text_end;
318+
319+
if (bootloader_util_regions_overlap(loader_iram_start, loader_iram_end,
320+
load_addr, load_end)) {
321+
ESP_LOGE(TAG, "Segment %d (0x%08x-0x%08x) overlaps bootloader IRAM (0x%08x-0x%08x)",
322+
index, load_addr, load_end, loader_iram_start, loader_iram_end);
297323
return ESP_ERR_IMAGE_INVALID;
298324
}
299325
}
300326
}
327+
#endif // BOOTLOADER_BUILD
328+
301329
#ifndef BOOTLOADER_BUILD
302330
uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
303331
ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count);

components/bootloader_support/test/test_verify_image.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "freertos/xtensa_api.h"
1414
#include "unity.h"
1515

16+
#include "bootloader_util.h"
1617
#include "esp_partition.h"
1718
#include "esp_ota_ops.h"
1819
#include "esp_image_format.h"
@@ -47,3 +48,21 @@ TEST_CASE("Verify unit test app image", "[bootloader_support]")
4748
TEST_ASSERT_TRUE(data.image_len <= running->size);
4849
}
4950

51+
TEST_CASE("Test regions_overlap", "[bootloader_support]")
52+
{
53+
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 1, 2) );
54+
55+
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 0, 2) );
56+
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 1, 3) );
57+
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 0, 3) );
58+
59+
TEST_ASSERT( bootloader_util_regions_overlap(0, 2, 1, 2) );
60+
TEST_ASSERT( bootloader_util_regions_overlap(1, 3, 1, 2) );
61+
TEST_ASSERT( bootloader_util_regions_overlap(0, 3, 1, 2) );
62+
63+
TEST_ASSERT( !bootloader_util_regions_overlap(2, 3, 1, 2) );
64+
TEST_ASSERT( !bootloader_util_regions_overlap(1, 2, 2, 3) );
65+
66+
TEST_ASSERT( !bootloader_util_regions_overlap(3, 4, 1, 2) );
67+
TEST_ASSERT( !bootloader_util_regions_overlap(1, 2, 3, 4) );
68+
}

0 commit comments

Comments
 (0)