loader: add checking of reset address

In a multi image context it is possible for a user to upload an image
to the wrong secondary slot. As the same key is used for both images
MCUboot will overwrite image 0 with a variant of image 1.

If direct overwrite is enabled it is not trivial to recover from this.

To mitigate this issue we introduce a check of the reset address within
the vector table.

If the reset address in the new image is not contained within the
primary slot the image is deemed incorrect and is deleted from the
secondary slot

Signed-off-by: Håkon Øye Amundsen <haakon.amundsen@nordicsemi.no>
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index af4d12e..a26159c 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -773,6 +773,41 @@
         goto out;
     }
 
+#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS)
+    /* Verify that the image in the secondary slot has a reset address
+     * located in the primary slot. This is done to avoid users incorrectly
+     * overwriting an application written to the incorrect slot.
+     * This feature is only supported by ARM platforms.
+     */
+    if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
+        const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
+        struct image_header *secondary_hdr = boot_img_hdr(state, slot);
+        uint32_t reset_value = 0;
+        uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value);
+
+        rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value));
+        if (rc != 0) {
+            fih_rc = fih_int_encode(1);
+            goto out;
+        }
+
+        if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
+            BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
+            BOOT_LOG_ERR("Erasing image from secondary slot");
+
+            /* The vector table in the image located in the secondary
+             * slot does not target the primary slot. This might
+             * indicate that the image was loaded to the wrong slot.
+             *
+             * Erase the image and continue booting from the primary slot.
+             */
+            flash_area_erase(fap, 0, fap->fa_size);
+            fih_rc = fih_int_encode(1);
+            goto out;
+        }
+    }
+#endif
+
 out:
     flash_area_close(fap);
 
diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig
index 0290476..2c585b9 100644
--- a/boot/zephyr/Kconfig
+++ b/boot/zephyr/Kconfig
@@ -257,9 +257,14 @@
 	  JTAG/SWD or primary slot in external flash).
 	  If unsure, leave at the default value.
 
+config BOOT_ENCRYPT_IMAGE
+	bool
+	help
+	  Hidden option used to check if any image encryption is enabled.
+
 config BOOT_ENCRYPT_RSA
 	bool "Support for encrypted upgrade images using RSA"
-	default n
+	select BOOT_ENCRYPT_IMAGE
 	help
 	  If y, images in the secondary slot can be encrypted and are decrypted
 	  on the fly when upgrading to the primary slot, as well as encrypted
@@ -268,7 +273,7 @@
 
 config BOOT_ENCRYPT_EC256
 	bool "Support for encrypted upgrade images using ECIES-P256"
-	default n
+	select BOOT_ENCRYPT_IMAGE
 	help
 	  If y, images in the secondary slot can be encrypted and are decrypted
 	  on the fly when upgrading to the primary slot, as well as encrypted
@@ -278,7 +283,7 @@
 
 config BOOT_ENCRYPT_X25519
 	bool "Support for encrypted upgrade images using ECIES-X25519"
-	default n
+	select BOOT_ENCRYPT_IMAGE
 	help
 	  If y, images in the secondary slot can be encrypted and are decrypted
 	  on the fly when upgrading to the primary slot, as well as encrypted
@@ -692,4 +697,22 @@
 	bool
 	default n
 
+config MCUBOOT_VERIFY_IMG_ADDRESS
+	bool "Verify reset address of image in secondary slot"
+	depends on UPDATEABLE_IMAGE_NUMBER > 1
+	depends on !BOOT_ENCRYPT_IMAGE
+	depends on ARM
+	default y if BOOT_UPGRADE_ONLY
+	help
+	  Verify that the reset address in the image located in the secondary slot
+	  is contained within the corresponding primary slot. This is recommended
+	  if swapping is not used (that is, BOOT_UPGRADE_ONLY is set). If a user
+	  incorrectly uploads an update for image 1 to image 0's secondary slot
+	  MCUboot will overwrite image 0's primary slot with this image even
+	  though it will not boot. If swapping is enabled this will be handled
+	  since the image will not confirm itself. If, however, swapping is not
+	  enabled then the only mitigation is serial recovery. This feature can
+	  also be useful when BOOT_DIRECT_XIP is enabled, to ensure that the image
+	  linked at the correct address is loaded.
+
 source "Kconfig.zephyr"
diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
index 7061fc1..7bbc7e9 100644
--- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h
+++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
@@ -168,6 +168,10 @@
 #define MCUBOOT_IMAGE_ACCESS_HOOKS
 #endif
 
+#ifdef CONFIG_MCUBOOT_VERIFY_IMG_ADDRESS
+#define MCUBOOT_VERIFY_IMG_ADDRESS
+#endif
+
 /*
  * The configuration option enables direct image upload with the
  * serial recovery.