Fix dependency check infinite loop

This fixes the issue where an unmet dependency would result in a restart
of image dependency checks. To make the code easier to follow, some
function nesting was removed, functions that check slot dependencies
were renamed appropriately and dependency check is not done when no
upgrades are marked.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index d95fdae..fc5b890 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -1825,8 +1825,8 @@
  * @return                  0 on success; nonzero on failure.
  */
 static int
-boot_verify_single_dependency(struct boot_loader_state *state,
-                              struct image_dependency *dep)
+boot_verify_slot_dependency(struct boot_loader_state *state,
+                            struct image_dependency *dep)
 {
     struct image_version *dep_version;
     size_t dep_slot;
@@ -1871,7 +1871,7 @@
  * @return                  0 on success; nonzero on failure.
  */
 static int
-boot_verify_all_dependency(struct boot_loader_state *state, uint32_t slot)
+boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
 {
     const struct flash_area *fap;
     struct image_tlv tlv;
@@ -1903,9 +1903,7 @@
          }
 
         if (tlv.it_type == IMAGE_TLV_DEPENDENCY) {
-            if (!dep_tlvs_found) {
-                dep_tlvs_found = true;
-            }
+            dep_tlvs_found = true;
 
             if (tlv.it_len != sizeof(dep)) {
                 rc = BOOT_EBADIMAGE;
@@ -1918,8 +1916,13 @@
                 goto done;
             }
 
+            if (dep.image_id >= BOOT_IMAGE_NUMBER) {
+                rc = BOOT_EBADARGS;
+                goto done;
+            }
+
             /* Verify dependency and modify the swap type if not satisfied. */
-            rc = boot_verify_single_dependency(state, &dep);
+            rc = boot_verify_slot_dependency(state, &dep);
             if (rc != 0) {
                 /* Dependency not satisfied. */
                 goto done;
@@ -1944,54 +1947,43 @@
 }
 
 /**
- * Verify whether the image dependencies in the TLV area are
- * all satisfied and modify the swap type if necessary.
- *
- * @return                  0 if all dependencies are satisfied,
- *                          nonzero otherwise.
- */
-static int
-boot_verify_single_image_dependency(struct boot_loader_state *state)
-{
-    size_t slot;
-
-    /* Determine the source of the dependency TLVs. Those dependencies have to
-     * be checked which belong to the image that will be located in the primary
-     * slot after the firmware update process.
-     */
-    if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
-        BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
-        slot = BOOT_SECONDARY_SLOT;
-    } else {
-        slot = BOOT_PRIMARY_SLOT;
-    }
-
-    return boot_verify_all_dependency(state, slot);
-}
-
-/**
  * Iterate over all the images and verify whether the image dependencies in the
  * TLV area are all satisfied and update the related swap type if necessary.
  */
-static void
-boot_verify_all_image_dependency(struct boot_loader_state *state)
+static int
+boot_verify_dependencies(struct boot_loader_state *state)
 {
     int rc;
+    uint8_t slot;
 
     BOOT_CURR_IMG(state) = 0;
     while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
-        rc = boot_verify_single_image_dependency(state);
+        if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
+            BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
+            slot = BOOT_SECONDARY_SLOT;
+        } else {
+            slot = BOOT_PRIMARY_SLOT;
+        }
+
+        rc = boot_verify_slot_dependencies(state, slot);
         if (rc == 0) {
             /* All dependencies've been satisfied, continue with next image. */
             BOOT_CURR_IMG(state)++;
         } else if (rc == BOOT_EBADVERSION) {
-            /* Dependency check needs to be restarted. */
-            BOOT_CURR_IMG(state) = 0;
+            /* Cannot upgrade due to non-met dependencies, so disable all
+             * image upgrades.
+             */
+            for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
+                BOOT_CURR_IMG(state) = idx;
+                BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
+            }
+            break;
         } else {
             /* Other error happened, images are inconsistent */
-            return;
+            return rc;
         }
     }
+    return rc;
 }
 #endif /* (BOOT_IMAGE_NUMBER > 1) */
 
@@ -2300,6 +2292,7 @@
     int rc;
     int fa_id;
     int image_index;
+    bool has_upgrade;
 
     /* The array of slot sectors are defined here (as opposed to file scope) so
      * that they don't get allocated for non-boot-loader apps.  This is
@@ -2311,6 +2304,11 @@
     TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
 
     memset(state, 0, sizeof(struct boot_loader_state));
+    has_upgrade = false;
+
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)has_upgrade;
+#endif
 
     /* Iterate over all the images. By the end of the loop the swap type has
      * to be determined for each image and all aborted swaps have to be
@@ -2348,13 +2346,28 @@
 
         /* Determine swap type and complete swap if it has been aborted. */
         boot_prepare_image_for_update(state, &bs);
+
+        if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
+            has_upgrade = true;
+        }
     }
 
 #if (BOOT_IMAGE_NUMBER > 1)
-    /* Iterate over all the images and verify whether the image dependencies
-     * are all satisfied and update swap type if necessary.
-     */
-    boot_verify_all_image_dependency(state);
+    if (has_upgrade) {
+        /* Iterate over all the images and verify whether the image dependencies
+         * are all satisfied and update swap type if necessary.
+         */
+        rc = boot_verify_dependencies(state);
+        if (rc == BOOT_EBADVERSION) {
+            /*
+             * It was impossible to upgrade because the expected dependency version
+             * was not available. Here we already changed the swap_type so that
+             * instead of asserting the bootloader, we continue and no upgrade is
+             * performed.
+             */
+            rc = 0;
+        }
+    }
 #endif
 
     /* Iterate over all the images. At this point there are no aborted swaps
@@ -2464,11 +2477,12 @@
     /* Always boot from the primary slot of Image 0. */
     BOOT_CURR_IMG(state) = 0;
 #endif
+
     rsp->br_flash_dev_id = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
     rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
     rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
 
- out:
+out:
     IMAGES_ITER(BOOT_CURR_IMG(state)) {
         flash_area_close(BOOT_SCRATCH_AREA(state));
         for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {