]> granicus.if.org Git - esp-idf/commitdiff
Bugfix: ota fails with secure boot on for image size greater than 3.2MB
authorVikram Dattu <vikram.dattu@espressif.com>
Sat, 15 Jun 2019 09:43:51 +0000 (15:13 +0530)
committerbot <bot@espressif.com>
Mon, 1 Jul 2019 20:04:15 +0000 (20:04 +0000)
When an OTA image size is larger than 50 MMU pages (approx. 3.2 MB), secure_boot_generate fails while trying to map it into memory:
https://gitlab.espressif.cn:6688/idf/esp-idf/blob/master/components/bootloader_support/src/esp32/secure_boot.c#L72
Instead of trying to map the whole image, secure boot code should split the image into chunks and map them one by one, like it is done in esp_image_format.c:
https://gitlab.espressif.cn:6688/idf/esp-idf/blob/master/components/bootloader_support/src/esp_image_format.c#L372

Closes https://jira.espressif.com:8443/browse/IDF-709

Signed-off-by: Vikram Dattu <vikram.dattu@espressif.com>
components/bootloader_support/include_bootloader/bootloader_flash.h
components/bootloader_support/src/bootloader_flash.c
components/bootloader_support/src/esp32/secure_boot_signatures.c

index ce867d7573b60314d04a3c8a9c2466b2749d4e3c..6ac7246462d827e9db78f6c38fb6353986768628 100644 (file)
    bootloader_support components only.
 */
 
+/**
+ * @brief Get number of free pages
+ *
+ * @return Number of free pages
+ */
+uint32_t bootloader_mmap_get_free_pages();
+
 /**
  * @brief Map a region of flash to data memory
  *
index 5b4a555e1c27e5ee7f402e3d84af27294ee07d7a..6b25addf225460b6af935f4ea087c70303549bb2 100644 (file)
@@ -25,6 +25,11 @@ static const char *TAG = "bootloader_mmap";
 
 static spi_flash_mmap_handle_t map;
 
+uint32_t bootloader_mmap_get_free_pages()
+{
+    return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
+}
+
 const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
 {
     if (map) {
@@ -91,12 +96,22 @@ static const char *TAG = "bootloader_flash";
 */
 #define MMU_BLOCK0_VADDR  0x3f400000
 #define MMU_BLOCK50_VADDR 0x3f720000
+#define MMU_FREE_PAGES    ((MMU_BLOCK50_VADDR - MMU_BLOCK0_VADDR) / FLASH_BLOCK_SIZE)
 
 static bool mapped;
 
 // Current bootloader mapping (ab)used for bootloader_read()
 static uint32_t current_read_mapping = UINT32_MAX;
 
+uint32_t bootloader_mmap_get_free_pages()
+{
+    /**
+     * Allow mapping up to 50 of the 51 available MMU blocks (last one used for reads)
+     * Since, bootloader_mmap function below assumes it to be 0x320000 (50 pages), we can safely do this.
+     */
+    return MMU_FREE_PAGES;
+}
+
 const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
 {
     if (mapped) {
index 3642b309dfc3acd75291511c67f97d2a7670a0b7..dbc32eab5f174d01910130ab9bd89eb8c267ef46 100644 (file)
@@ -21,7 +21,7 @@
 #include "esp32/rom/sha.h"
 #include "uECC.h"
 
-typedef SHA_CTX sha_context;
+#include <sys/param.h>
 
 static const char *TAG = "secure_boot";
 
@@ -32,6 +32,9 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver
 
 #define DIGEST_LEN 32
 
+/* Mmap source address mask */
+#define MMAP_ALIGNED_MASK 0x0000FFFF
+
 esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
 {
     uint8_t digest[DIGEST_LEN];
@@ -40,21 +43,44 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
 
     ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
 
-    data = bootloader_mmap(src_addr, length + sizeof(esp_secure_boot_sig_block_t));
-    if (data == NULL) {
-        ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length + sizeof(esp_secure_boot_sig_block_t));
-        return ESP_FAIL;
+    bootloader_sha256_handle_t handle = bootloader_sha256_start();
+
+    uint32_t free_page_count = bootloader_mmap_get_free_pages();
+    ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count);
+
+    int32_t data_len_remain = length;
+    uint32_t data_addr = src_addr;
+    while (data_len_remain > 0) {
+        uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
+        /* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */
+        uint32_t data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
+        data = (const uint8_t *) bootloader_mmap(data_addr, data_len);
+        if(!data) {
+            ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", data_addr, data_len);
+            bootloader_sha256_finish(handle, NULL);
+            return ESP_FAIL;
+        }
+        bootloader_sha256_data(handle, data, data_len);
+        bootloader_munmap(data);
+
+        data_addr += data_len;
+        data_len_remain -= data_len;
     }
 
-    // Calculate digest of main image
-    bootloader_sha256_handle_t handle = bootloader_sha256_start();
-    bootloader_sha256_data(handle, data, length);
+    /* Done! Get the digest */
     bootloader_sha256_finish(handle, digest);
 
-    // Map the signature block and verify the signature
-    sigblock = (const esp_secure_boot_sig_block_t *)(data + length);
+    // Map the signature block
+    sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t));
+    if(!sigblock) {
+        ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t));
+        return ESP_FAIL;
+    }
+    // Verify the signature
     esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest);
-    bootloader_munmap(data);
+    // Unmap
+    bootloader_munmap(sigblock);
+
     return err;
 }