Repository: chipsalliance/caliptra-sw
Pull request #499 (2023-07-17 21:10:21)

[fix] Additional checks for FMC and Runtime in the Verifier library
This change adds the following checks to the Firmware Image Verifier Library:
	1. Checks if FMC and Runtime sizes are not zero in the TOCs.
	2. Checks if FMC and Runtime are fully contained in the ICCM.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 50fff8ee..4a7e6e1d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -463,6 +463,7 @@ dependencies = [
  "bitflags 2.0.2",
  "caliptra-drivers",
  "caliptra-image-types",
+ "caliptra_common",
  "memoffset",
  "zerocopy",
 ]
diff --git a/error/src/lib.rs b/error/src/lib.rs
index 96b67dc5..a806144b 100644
--- a/error/src/lib.rs
+++ b/error/src/lib.rs
@@ -232,6 +232,10 @@ impl CaliptraError {
     pub const RUNTIME_HANDOFF_FHT_NOT_LOADED: CaliptraError = CaliptraError::new_const(0x000b0039);
     pub const IMAGE_VERIFIER_ERR_VENDOR_LMS_PUB_KEY_REVOKED: CaliptraError =
         CaliptraError::new_const(0x000b0003a);
+    pub const IMAGE_VERIFIER_ERR_FMC_SIZE_ZERO: CaliptraError =
+        CaliptraError::new_const(0x000b003b);
+    pub const IMAGE_VERIFIER_ERR_RUNTIME_SIZE_ZERO: CaliptraError =
+        CaliptraError::new_const(0x000b003c);
 
     /// Driver Error: LMS
     pub const DRIVER_LMS_INVALID_LMS_ALGO_TYPE: CaliptraError =
diff --git a/image/verify/Cargo.toml b/image/verify/Cargo.toml
index bff154c6..2fc09f7f 100644
--- a/image/verify/Cargo.toml
+++ b/image/verify/Cargo.toml
@@ -15,6 +15,9 @@ caliptra-image-types = { workspace = true, default-features = false }
 memoffset.workspace = true
 zerocopy.workspace = true
 
+[dev-dependencies]
+caliptra_common = { path = "../../common", default-features = false }
+
 [features]
 default = ["std"]
 std = ["caliptra-image-types/std"]
diff --git a/image/verify/src/verifier.rs b/image/verify/src/verifier.rs
index bcf925aa..80a509a0 100644
--- a/image/verify/src/verifier.rs
+++ b/image/verify/src/verifier.rs
@@ -499,6 +499,16 @@ impl<Env: ImageVerificationEnv> ImageVerifier<Env> {
             Err(CaliptraError::IMAGE_VERIFIER_ERR_TOC_DIGEST_MISMATCH)?;
         }
 
+        // Verify the FMC size is not zero.
+        if manifest.fmc.image_size() == 0 {
+            Err(CaliptraError::IMAGE_VERIFIER_ERR_FMC_SIZE_ZERO)?;
+        }
+
+        // Verify the Runtime size is not zero.
+        if manifest.runtime.image_size() == 0 {
+            Err(CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_SIZE_ZERO)?;
+        }
+
         // Image length does not exceed the Image Bundle size
         let img_len: u64 = manifest.size as u64
             + manifest.fmc.image_size() as u64
@@ -563,9 +573,12 @@ impl<Env: ImageVerificationEnv> ImageVerifier<Env> {
             Err(CaliptraError::IMAGE_VERIFIER_ERR_FMC_DIGEST_MISMATCH)?;
         }
 
-        // TODO: Perform following Address check
-        // Entry Point is within the image
-        if !self.env.iccm_range().contains(&verify_info.load_addr) {
+        if !self.env.iccm_range().contains(&verify_info.load_addr)
+            || !self
+                .env
+                .iccm_range()
+                .contains(&(verify_info.load_addr + verify_info.size - 1))
+        {
             Err(CaliptraError::IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_INVALID)?;
         }
         if verify_info.load_addr % 4 != 0 {
@@ -634,10 +647,12 @@ impl<Env: ImageVerificationEnv> ImageVerifier<Env> {
             Err(CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_DIGEST_MISMATCH)?;
         }
 
-        // TODO: Perform following Address checks
-        // 3. Entry Point is within the image
-
-        if !self.env.iccm_range().contains(&verify_info.load_addr) {
+        if !self.env.iccm_range().contains(&verify_info.load_addr)
+            || !self
+                .env
+                .iccm_range()
+                .contains(&(verify_info.load_addr + verify_info.size - 1))
+        {
             Err(CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_LOAD_ADDR_INVALID)?;
         }
         if verify_info.load_addr % 4 != 0 {
@@ -720,6 +735,7 @@ impl<Env: ImageVerificationEnv> ImageVerifier<Env> {
 #[cfg(all(test, target_family = "unix"))]
 mod tests {
     use super::*;
+    use caliptra_common::memory_layout::*;
 
     const DUMMY_DATA: [u32; 12] = [
         0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
@@ -813,8 +829,9 @@ mod tests {
 
         let verify_info = ImageTocEntry {
             digest: DUMMY_DATA,
-            load_addr: 0x40000000,
-            entry_point: 0x40000000,
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
+            size: 100,
             ..Default::default()
         };
 
@@ -835,8 +852,9 @@ mod tests {
         let mut verifier = ImageVerifier::new(test_env);
         let verify_info = ImageTocEntry {
             digest: DUMMY_DATA,
-            load_addr: 0x40000000,
-            entry_point: 0x40000000,
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
+            size: 100,
             ..Default::default()
         };
 
@@ -1406,6 +1424,28 @@ mod tests {
             digest: &ImageDigest::default(),
         };
 
+        // FMC size == 0
+        manifest.fmc.offset = 0;
+        manifest.fmc.size = 0;
+        manifest.runtime.offset = 100;
+        manifest.runtime.size = 200;
+        let result = verifier.verify_toc(&manifest, &toc_info, 500);
+        assert_eq!(
+            result.err(),
+            Some(CaliptraError::IMAGE_VERIFIER_ERR_FMC_SIZE_ZERO)
+        );
+
+        // RT size == 0
+        manifest.fmc.offset = 0;
+        manifest.fmc.size = 100;
+        manifest.runtime.offset = 100;
+        manifest.runtime.size = 0;
+        let result = verifier.verify_toc(&manifest, &toc_info, 500);
+        assert_eq!(
+            result.err(),
+            Some(CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_SIZE_ZERO)
+        );
+
         // [-FMC--]
         // [--RT--]
         manifest.fmc.offset = 0;
@@ -1524,6 +1564,34 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_fmc_contained_in_iccm() {
+        let test_env = TestEnv::default();
+        let mut verifier = ImageVerifier::new(test_env);
+        let verify_info = ImageTocEntry {
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
+            size: ICCM_SIZE + 1,
+            ..Default::default()
+        };
+
+        let result = verifier.verify_fmc(&verify_info, ResetReason::ColdReset);
+        assert_eq!(
+            result.err(),
+            Some(CaliptraError::IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_INVALID)
+        );
+
+        let verify_info = ImageTocEntry {
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
+            size: ICCM_SIZE,
+            ..Default::default()
+        };
+
+        let result = verifier.verify_fmc(&verify_info, ResetReason::ColdReset);
+        assert_eq!(result.err(), None);
+    }
+
     #[test]
     fn test_fmc_digest_mismatch() {
         let test_env = TestEnv::default();
@@ -1544,8 +1612,8 @@ mod tests {
         let test_env = TestEnv::default();
         let mut verifier = ImageVerifier::new(test_env);
         let verify_info = ImageTocEntry {
-            load_addr: 0x40000000,
-            entry_point: 0x40000000,
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
             svn: 1,
             size: 100,
             ..Default::default()
@@ -1554,8 +1622,8 @@ mod tests {
         let result = verifier.verify_fmc(&verify_info, ResetReason::ColdReset);
         assert!(result.is_ok());
         let (info, _log_info) = result.unwrap();
-        assert_eq!(info.load_addr, 0x40000000);
-        assert_eq!(info.entry_point, 0x40000000);
+        assert_eq!(info.load_addr, ICCM_ORG);
+        assert_eq!(info.entry_point, ICCM_ORG);
         assert_eq!(info.svn, 1);
         assert_eq!(info.size, 100);
     }
@@ -1575,13 +1643,41 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_rt_contained_in_iccm() {
+        let test_env = TestEnv::default();
+        let mut verifier = ImageVerifier::new(test_env);
+        let verify_info = ImageTocEntry {
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
+            size: ICCM_SIZE + 1,
+            ..Default::default()
+        };
+
+        let result = verifier.verify_runtime(&verify_info);
+        assert_eq!(
+            result.err(),
+            Some(CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_LOAD_ADDR_INVALID)
+        );
+
+        let verify_info = ImageTocEntry {
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
+            size: ICCM_SIZE,
+            ..Default::default()
+        };
+
+        let result = verifier.verify_runtime(&verify_info);
+        assert_eq!(result.err(), None);
+    }
+
     #[test]
     fn test_rt_success() {
         let test_env = TestEnv::default();
         let mut verifier = ImageVerifier::new(test_env);
         let verify_info = ImageTocEntry {
-            load_addr: 0x40000000,
-            entry_point: 0x40000000,
+            load_addr: ICCM_ORG,
+            entry_point: ICCM_ORG,
             svn: 1,
             size: 100,
             ..Default::default()
@@ -1589,8 +1685,8 @@ mod tests {
         let result = verifier.verify_runtime(&verify_info);
         assert!(result.is_ok());
         let (info, _log_info) = result.unwrap();
-        assert_eq!(info.load_addr, 0x40000000);
-        assert_eq!(info.entry_point, 0x40000000);
+        assert_eq!(info.load_addr, ICCM_ORG);
+        assert_eq!(info.entry_point, ICCM_ORG);
         assert_eq!(info.svn, 1);
         assert_eq!(info.size, 100);
     }
@@ -1700,8 +1796,8 @@ mod tests {
 
         fn iccm_range(&self) -> Range<u32> {
             Range {
-                start: 0x40000000,
-                end: 0x40000000 + (128 * 1024),
+                start: ICCM_ORG,
+                end: ICCM_ORG + ICCM_SIZE,
             }
         }
 
diff --git a/rom/dev/src/rom_env.rs b/rom/dev/src/rom_env.rs
index 93c4c0af..2055d396 100644
--- a/rom/dev/src/rom_env.rs
+++ b/rom/dev/src/rom_env.rs
@@ -16,6 +16,7 @@ Abstract:
 --*/
 
 use crate::fht::FhtDataStore;
+use caliptra_common::memory_layout::*;
 use caliptra_drivers::{
     DataVault, DeobfuscationEngine, Ecc384, Hmac384, KeyVault, Lms, Mailbox, PcrBank, Sha1, Sha256,
     Sha384, Sha384Acc, SocIfc, Trng,
@@ -28,9 +29,6 @@ use caliptra_registers::{
 };
 use core::ops::Range;
 
-const ICCM_START: u32 = 0x40000000;
-const ICCM_SIZE: u32 = 128 << 10;
-
 /// Rom Context
 pub struct RomEnv {
     /// Deobfuscation engine
@@ -81,8 +79,8 @@ pub struct RomEnv {
 
 impl RomEnv {
     pub const ICCM_RANGE: Range<u32> = Range {
-        start: ICCM_START,
-        end: ICCM_START + ICCM_SIZE,
+        start: ICCM_ORG,
+        end: ICCM_ORG + ICCM_SIZE,
     };
 
     pub unsafe fn new_from_registers() -> CaliptraResult<Self> {


Test patch:
diff --git a/rom/dev/doc/test-coverage/test-coverage.md b/rom/dev/doc/test-coverage/test-coverage.md
index 17f7ae6d..59006f7e 100644
--- a/rom/dev/doc/test-coverage/test-coverage.md
+++ b/rom/dev/doc/test-coverage/test-coverage.md
@@ -37,12 +37,14 @@ IMAGE_VERIFIER_ERR_VENDOR_LMS_PUBKEY_INDEX_OUT_OF_BOUNDS
 **test_header_verify_owner_ecc_sig_invalid_signature_s** | Image Verification - Header | Checks if owner ECC signature.s from Preamble and computed header signature match | IMAGE_VERIFIER_ERR_OWNER_ECC_SIGNATURE_INVALID
 **test_toc_invalid_entry_count** | Image Verification - TOC | Checks if header.toc_count equals MAX_TOC_ENTRY_COUNT (2) | IMAGE_VERIFIER_ERR_TOC_ENTRY_COUNT_INVALID
 **test_toc_invalid_toc_digest** | Image Verification - TOC | Checks if digest of [manifest.fmc_toc | manifest.rt_toc] matches header.toc_digest | IMAGE_VERIFIER_ERR_TOC_DIGEST_MISMATCH
+**test_toc_fmc_size_zero** | Image Verification - TOC | Checks if FMC size if zero | IMAGE_VERIFIER_ERR_FMC_SIZE_ZERO
 **test_toc_fmc_range_overlap** | Image Verification - TOC | Checks if FMC and Runtime images don't overlap in the image bundle | IMAGE_VERIFIER_ERR_FMC_RUNTIME_OVERLAP
 **test_toc_fmc_range_incorrect_order** | Image Verification - TOC | Checks if FMC image is before Runtime image in the image bundle | IMAGE_VERIFIER_ERR_FMC_RUNTIME_INCORRECT_ORDER
 **test_fmc_rt_load_address_range_overlap** | Image Verification - TOC | Checks if FMC and Runtime image load address range don't overlap | IMAGE_VERIFIER_ERR_FMC_RUNTIME_LOAD_ADDR_OVERLAP
 **test_fmc_digest_mismatch** | Image Verification - FMC | Checks if manifest.fmc_toc.digest matches FMC image digest | IMAGE_VERIFIER_ERR_FMC_DIGEST_MISMATCH
 **test_fmc_invalid_load_addr_before_iccm** | Image Verification - FMC | Checks if FMC load address is within ICCM range | IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_INVALID
 **test_fmc_invalid_load_addr_after_iccm** | Image Verification - FMC | Checks if FMC load address is within ICCM range | IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_INVALID
+**test_fmc_not_contained_in_iccm** | Image Verification - FMC | Checks if FMC is fully contained in the ICCM | IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_INVALID
 **test_fmc_load_addr_unaligned** | Image Verification - FMC | Checks if FMC load address is DWORD aligned | IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_UNALIGNED
 **test_fmc_invalid_entry_point_before_iccm** | Image Verification - FMC | Checks if FMC entry point is within ICCM range  | IMAGE_VERIFIER_ERR_FMC_ENTRY_POINT_INVALID
 **test_fmc_invalid_entry_point_after_iccm** | Image Verification - FMC | Checks if FMC entry point is within ICCM range  | IMAGE_VERIFIER_ERR_FMC_ENTRY_POINT_INVALID
@@ -50,9 +52,11 @@ IMAGE_VERIFIER_ERR_VENDOR_LMS_PUBKEY_INDEX_OUT_OF_BOUNDS
 **test_fmc_svn_greater_than_32** | Image Verification - FMC | Checks if FMC SVN is greater than max (32) | IMAGE_VERIFIER_ERR_FMC_SVN_GREATER_THAN_MAX_SUPPORTED
 **test_fmc_svn_less_than_min_svn** | Image Verification - FMC | Checks if FMC SVN is less than toc_fmc.min_svn | IMAGE_VERIFIER_ERR_FMC_SVN_LESS_THAN_MIN_SUPPORTED
 **test_fmc_svn_less_than_fuse_svn** | Image Verification - FMC | Checks if FMC SVN is less than fuse svn | IMAGE_VERIFIER_ERR_FMC_SVN_LESS_THAN_FUSE
+**test_toc_rt_size_zero** | Image Verification - RT | Checks if RT size if 0 | IMAGE_VERIFIER_ERR_RUNTIME_SIZE_ZERO
 **test_runtime_digest_mismatch** | Image Verification - RT | Checks if manifest.rt_toc.digest matches Runtime image digest | IMAGE_VERIFIER_ERR_RUNTIME_DIGEST_MISMATCH
 **test_runtime_invalid_load_addr_before_iccm** | Image Verification - RT | Checks if RT load address is within ICCM range | IMAGE_VERIFIER_ERR_RUNTIME_LOAD_ADDR_INVALID
 **test_runtime_invalid_load_addr_after_iccm** | Image Verification - RT | Checks if RT load address is within ICCM range | IMAGE_VERIFIER_ERR_RUNTIME_LOAD_ADDR_INVALID
+**test_runtime_not_contained_in_iccm** | Image Verification - RT | Checks if RT is fully contained in the ICCM | IMAGE_VERIFIER_ERR_RUNTIME_LOAD_ADDR_INVALID
 **test_runtime_load_addr_unaligned** | Image Verification - RT | Checks if RT load address is DWORD aligned | IMAGE_VERIFIER_ERR_RUNTIME_LOAD_ADDR_UNALIGNED
 **test_runtime_invalid_entry_point_before_iccm** | Image Verification - RT | Checks if RT entry point is within ICCM range  | IMAGE_VERIFIER_ERR_RUNTIME_ENTRY_POINT_INVALID
 **test_runtime_invalid_entry_point_after_iccm** | Image Verification - RT | Checks if RT entry point is within ICCM range  | IMAGE_VERIFIER_ERR_RUNTIME_ENTRY_POINT_INVALID
diff --git a/rom/dev/tests/test_image_validation.rs b/rom/dev/tests/test_image_validation.rs
index 4a8e7db2..b42bfa05 100644
--- a/rom/dev/tests/test_image_validation.rs
+++ b/rom/dev/tests/test_image_validation.rs
@@ -2,6 +2,7 @@
 
 use caliptra_builder::FwId;
 use caliptra_builder::{ImageOptions, APP_WITH_UART, FMC_WITH_UART, ROM_WITH_UART};
+use caliptra_common::memory_layout::{ICCM_ORG, ICCM_SIZE};
 use caliptra_common::RomBootStatus::ColdResetComplete;
 use caliptra_drivers::Array4x12;
 use caliptra_drivers::MfgFlags;
@@ -31,8 +32,7 @@ use zerocopy::AsBytes;
 
 pub mod helpers;
 
-const ICCM_START_ADDR: u32 = 0x40000000;
-const ICCM_END_ADDR: u32 = ICCM_START_ADDR + (128 * 1024) - 1;
+const ICCM_END_ADDR: u32 = ICCM_ORG + ICCM_SIZE - 1;
 
 const PUB_KEY_X: [u8; 48] = [
     0xD7, 0x9C, 0x6D, 0x97, 0x2B, 0x34, 0xA1, 0xDF, 0xC9, 0x16, 0xA7, 0xB6, 0xE0, 0xA9, 0x9B, 0x6B,
@@ -1025,6 +1025,29 @@ fn test_toc_invalid_toc_digest() {
     );
 }
 
+#[test]
+fn test_toc_fmc_size_zero() {
+    let (mut hw, mut image_bundle) =
+        helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
+    let fmc_new_size = 0;
+    // These are unchanged.
+    let fmc_new_offset = image_bundle.manifest.fmc.offset;
+    let runtime_new_offset = image_bundle.manifest.runtime.offset;
+    let runtime_new_size = image_bundle.manifest.runtime.size;
+
+    let image = update_fmc_runtime_ranges(
+        &mut image_bundle,
+        fmc_new_offset,
+        fmc_new_size,
+        runtime_new_offset,
+        runtime_new_size,
+    );
+    assert_eq!(
+        ModelError::MailboxCmdFailed(CaliptraError::IMAGE_VERIFIER_ERR_FMC_SIZE_ZERO.into()),
+        hw.upload_firmware(&image).unwrap_err()
+    );
+}
+
 #[test]
 fn test_toc_fmc_range_overlap() {
     // Case 1: FMC offset == Runtime offset
@@ -1166,7 +1189,7 @@ fn test_fmc_invalid_load_addr_before_iccm() {
     let (mut hw, mut image_bundle) =
         helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
 
-    let image = update_load_addr(&mut image_bundle, true, ICCM_START_ADDR - 4);
+    let image = update_load_addr(&mut image_bundle, true, ICCM_ORG - 4);
     assert_eq!(
         ModelError::MailboxCmdFailed(
             CaliptraError::IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_INVALID.into()
@@ -1189,6 +1212,20 @@ fn test_fmc_invalid_load_addr_after_iccm() {
     );
 }
 
+#[test]
+fn test_fmc_not_contained_in_iccm() {
+    let (mut hw, mut image_bundle) =
+        helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
+
+    let image = update_load_addr(&mut image_bundle, true, ICCM_END_ADDR - 4);
+    assert_eq!(
+        ModelError::MailboxCmdFailed(
+            CaliptraError::IMAGE_VERIFIER_ERR_FMC_LOAD_ADDR_INVALID.into()
+        ),
+        hw.upload_firmware(&image).unwrap_err()
+    );
+}
+
 #[test]
 fn test_fmc_load_addr_unaligned() {
     let (mut hw, mut image_bundle) =
@@ -1208,7 +1245,7 @@ fn test_fmc_invalid_entry_point_before_iccm() {
     let (mut hw, mut image_bundle) =
         helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
 
-    let image = update_entry_point(&mut image_bundle, true, ICCM_START_ADDR - 4);
+    let image = update_entry_point(&mut image_bundle, true, ICCM_ORG - 4);
     assert_eq!(
         ModelError::MailboxCmdFailed(
             CaliptraError::IMAGE_VERIFIER_ERR_FMC_ENTRY_POINT_INVALID.into()
@@ -1340,6 +1377,31 @@ fn test_fmc_svn_less_than_fuse_svn() {
     );
 }
 
+#[test]
+fn test_toc_rt_size_zero() {
+    let (mut hw, mut image_bundle) =
+        helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
+
+    let runtime_new_size = 0;
+
+    // These are unchanged.
+    let fmc_new_size = image_bundle.manifest.fmc.size;
+    let fmc_new_offset = image_bundle.manifest.fmc.offset;
+    let runtime_new_offset = image_bundle.manifest.runtime.offset;
+
+    let image = update_fmc_runtime_ranges(
+        &mut image_bundle,
+        fmc_new_offset,
+        fmc_new_size,
+        runtime_new_offset,
+        runtime_new_size,
+    );
+    assert_eq!(
+        ModelError::MailboxCmdFailed(CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_SIZE_ZERO.into()),
+        hw.upload_firmware(&image).unwrap_err()
+    );
+}
+
 #[test]
 fn test_runtime_digest_mismatch() {
     let (mut hw, mut image_bundle) =
@@ -1361,9 +1423,8 @@ fn test_runtime_invalid_load_addr_before_iccm() {
     let (mut hw, mut image_bundle) =
         helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
 
-    let rt_new_load_addr = ICCM_START_ADDR
-        - (image_bundle.manifest.fmc.load_addr - ICCM_START_ADDR
-            + image_bundle.manifest.runtime.size);
+    let rt_new_load_addr = ICCM_ORG
+        - (image_bundle.manifest.fmc.load_addr - ICCM_ORG + image_bundle.manifest.runtime.size);
     let image = update_load_addr(&mut image_bundle, false, rt_new_load_addr);
     assert_eq!(
         ModelError::MailboxCmdFailed(
@@ -1387,6 +1448,20 @@ fn test_runtime_invalid_load_addr_after_iccm() {
     );
 }
 
+#[test]
+fn test_runtime_not_contained_in_iccm() {
+    let (mut hw, mut image_bundle) =
+        helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
+
+    let image = update_load_addr(&mut image_bundle, false, ICCM_END_ADDR - 3);
+    assert_eq!(
+        ModelError::MailboxCmdFailed(
+            CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_LOAD_ADDR_INVALID.into()
+        ),
+        hw.upload_firmware(&image).unwrap_err()
+    );
+}
+
 #[test]
 fn test_runtime_load_addr_unaligned() {
     let (mut hw, mut image_bundle) =
@@ -1406,7 +1481,7 @@ fn test_runtime_invalid_entry_point_before_iccm() {
     let (mut hw, mut image_bundle) =
         helpers::build_hw_model_and_image_bundle(Fuses::default(), ImageOptions::default());
 
-    let image = update_entry_point(&mut image_bundle, false, ICCM_START_ADDR - 4);
+    let image = update_entry_point(&mut image_bundle, false, ICCM_ORG - 4);
     assert_eq!(
         ModelError::MailboxCmdFailed(
             CaliptraError::IMAGE_VERIFIER_ERR_RUNTIME_ENTRY_POINT_INVALID.into()