]> granicus.if.org Git - esp-idf/commitdiff
ota ops: Verify partition argument passed to esp_ota_begin()
authorAngus Gratton <angus@espressif.com>
Mon, 20 Feb 2017 05:02:29 +0000 (16:02 +1100)
committerAngus Gratton <angus@espressif.com>
Tue, 21 Feb 2017 23:26:04 +0000 (10:26 +1100)
components/app_update/esp_ota_ops.c
components/app_update/include/esp_ota_ops.h
components/spi_flash/include/esp_partition.h
components/spi_flash/partition.c

index ca46765c79131e7ccd368bef7fd83ba1c48ec7c6..f9d54576728e0cef172d0bec23baf3395c67a164 100644 (file)
@@ -43,7 +43,7 @@
 
 typedef struct ota_ops_entry_ {
     uint32_t handle;
-    esp_partition_t part;
+    const esp_partition_t *part;
     uint32_t erased_size;
     uint32_t wrote_size;
 #ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
@@ -69,21 +69,35 @@ static ota_select s_ota_select[2];
 
 const static char *TAG = "esp_ota_ops";
 
+/* Return true if this is an OTA app partition */
+static bool is_ota_partition(const esp_partition_t *p)
+{
+    return (p != NULL
+            && p->type == ESP_PARTITION_TYPE_APP
+            && p->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_0
+            && p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX);
+}
+
 esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle)
 {
+    ota_ops_entry_t *new_entry;
     esp_err_t ret = ESP_OK;
 
     if ((partition == NULL) || (out_handle == NULL)) {
         return ESP_ERR_INVALID_ARG;
     }
-    if (partition == esp_ota_get_running_partition()) {
-        return ESP_ERR_OTA_PARTITION_CONFLICT;
+
+    partition = esp_partition_verify(partition);
+    if (partition == NULL) {
+        return ESP_ERR_NOT_FOUND;
     }
 
-    ota_ops_entry_t *new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1);
+    if (!is_ota_partition(partition)) {
+        return ESP_ERR_INVALID_ARG;
+    }
 
-    if (new_entry == 0) {
-        return ESP_ERR_NO_MEM;
+    if (partition == esp_ota_get_running_partition()) {
+        return ESP_ERR_OTA_PARTITION_CONFLICT;
     }
 
     // If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition
@@ -94,11 +108,14 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
     }
 
     if (ret != ESP_OK) {
-        free(new_entry);
-        new_entry = NULL;
         return ret;
     }
 
+    new_entry = (ota_ops_entry_t *) calloc(sizeof(ota_ops_entry_t), 1);
+    if (new_entry == NULL) {
+        return ESP_ERR_NO_MEM;
+    }
+
     LIST_INSERT_HEAD(&s_ota_ops_entries_head, new_entry, entries);
 
     if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
@@ -107,7 +124,7 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
         new_entry->erased_size = image_size;
     }
 
-    memcpy(&new_entry->part, partition, sizeof(esp_partition_t));
+    new_entry->part = partition;
     new_entry->handle = ++s_ota_ops_last_handle;
     *out_handle = new_entry->handle;
     return ESP_OK;
@@ -169,7 +186,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
             }
 #endif
 
-            ret = esp_partition_write(&it->part, it->wrote_size, data_bytes, size);
+            ret = esp_partition_write(it->part, it->wrote_size, data_bytes, size);
             if(ret == ESP_OK){
                 it->wrote_size += size;
             }
@@ -219,13 +236,13 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
     }
 #endif
 
-    if (esp_image_basic_verify(it->part.address, true, &image_size) != ESP_OK) {
+    if (esp_image_basic_verify(it->part->address, true, &image_size) != ESP_OK) {
         ret = ESP_ERR_OTA_VALIDATE_FAILED;
         goto cleanup;
     }
 
 #ifdef CONFIG_SECURE_BOOT_ENABLED
-    ret = esp_secure_boot_verify_signature(it->part.address, image_size);
+    ret = esp_secure_boot_verify_signature(it->part->address, image_size);
     if (ret != ESP_OK) {
         ret = ESP_ERR_OTA_VALIDATE_FAILED;
         goto cleanup;
@@ -474,8 +491,8 @@ const esp_partition_t* esp_ota_get_running_partition(void)
         }
         it = esp_partition_next(it);
     }
-    esp_partition_iterator_release(it);
-    return NULL;
+
+    abort(); /* Partition table is invalid or corrupt */
 }
 
 
@@ -485,13 +502,16 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *
     bool next_is_result = false;
     if (start_from == NULL) {
         start_from = esp_ota_get_running_partition();
+    } else {
+        start_from = esp_partition_verify(start_from);
     }
     assert (start_from != NULL);
+    /* at this point, 'start_from' points to actual partition table data in flash */
+
 
-    /* Two possibilities: either we want the OTA partition immediately after the
-       current running OTA partition, or we want the first OTA partition we see (for
-       the case when the last OTA partition is the running partition, or if the current
-       running partition is not OTA.)
+    /* Two possibilities: either we want the OTA partition immediately after the current running OTA partition, or we
+       want the first OTA partition in the table (for the case when the last OTA partition is the running partition, or
+       if the current running partition is not OTA.)
     */
 
     esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP,
@@ -499,19 +519,21 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *
                                                      NULL);
     while (it != NULL) {
         const esp_partition_t *p = esp_partition_get(it);
-        if(p->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_0
-           && p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {
-            /* is OTA partition */
-            if (p == start_from || p->address == start_from->address) {
-                next_is_result = true; /* next OTA partition is the one */
+        if(is_ota_partition(p)) {
+            if (result == NULL) {
+                /* Default to first OTA partition we find,
+                 will be used if nothing else matches */
+                result = p;
+            }
+
+            if (p == start_from) {
+                /* Next OTA partition is the one to use */
+                next_is_result = true;
             }
             else if (next_is_result) {
                 result = p; /* this is it! */
                 break;
             }
-            else if (result == NULL) {
-                result = p; /* first OTA partition is the fallback */
-            }
         }
         it = esp_partition_next(it);
     }
index 8f99b23300ede48ee53d25b7c1f095b41d888092..33c03030aa025602265655654d77bbe1dd4c64f9 100755 (executable)
@@ -59,7 +59,7 @@ typedef uint32_t esp_ota_handle_t;
 
  * @return
  *    - ESP_OK: OTA operation commenced successfully.
- *    - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL, or partition doesn't point to a non OTA app partition.
+ *    - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL, or partition doesn't point to an OTA app partition.
  *    - ESP_ERR_NO_MEM: Cannot allocate memory for OTA operation.
  *    - ESP_ERR_OTA_PARTITION_CONFLICT: Partition holds the currently running firmware, cannot update in place.
  *    - ESP_ERR_NOT_FOUND: Partition argument not found in partition table.
index ba1327ab744055bb6c4a75e112c543b056c75bbb..f3d5a424af21f0398e85f741de78a3206b0d701a 100644 (file)
@@ -165,6 +165,26 @@ esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t iterator);
  */
 void esp_partition_iterator_release(esp_partition_iterator_t iterator);
 
+/**
+ * @brief Verify partition data
+ *
+ * Given a pointer to partition data, verify this partition exists in the partition table (all fields match.)
+ *
+ * This function is also useful to take partition data which may be in a RAM buffer and convert it to a pointer to the
+ * permanent partition data stored in flash.
+ *
+ * Pointers returned from this function can be compared directly to the address of any pointer returned from
+ * esp_partition_get(), as a test for equality.
+ *
+ * @param partition Pointer to partition data to verify. Must be non-NULL. All fields of this structure must match the
+ * partition table entry in flash for this function to return a successful match.
+ *
+ * @return
+ * - If partition not found, returns NULL.
+ * - If found, returns a pointer to the esp_partition_t structure in flash. This pointer is always valid for the lifetime of the application.
+ */
+const esp_partition_t *esp_partition_verify(const esp_partition_t *partition);
+
 /**
  * @brief Read data from the partition
  *
index 76036b305e6738d891d38e629616e163d31c8f45..58153cd7f0058fbd90fec6ef02b0bcb7c0ef719b 100644 (file)
@@ -200,6 +200,28 @@ const esp_partition_t* esp_partition_get(esp_partition_iterator_t iterator)
     return iterator->info;
 }
 
+const esp_partition_t *esp_partition_verify(const esp_partition_t *partition)
+{
+    assert(partition != NULL);
+    const char *label = (strlen(partition->label) > 0) ? partition->label : NULL;
+    esp_partition_iterator_t it = esp_partition_find(partition->type,
+                                                     partition->subtype,
+                                                     label);
+    while (it != NULL) {
+        const esp_partition_t *p = esp_partition_get(it);
+        /* Can't memcmp() whole structure here as padding contents may be different */
+        if (p->address == partition->address
+            && partition->size == p->size
+            && partition->encrypted == p->encrypted) {
+            esp_partition_iterator_release(it);
+            return p;
+        }
+        it = esp_partition_next(it);
+    }
+    esp_partition_iterator_release(it);
+    return NULL;
+}
+
 esp_err_t esp_partition_read(const esp_partition_t* partition,
         size_t src_offset, void* dst, size_t size)
 {