From 6945bb6cb4d1feda4bdb0a8504c3da76f5ffd3e8 Mon Sep 17 00:00:00 2001 From: Roland Mikhel Date: Tue, 11 Apr 2023 15:57:49 +0200 Subject: [PATCH] sim: Add new ram-load test cases Adds new test cases to various ram-load related logic. Signed-off-by: Roland Mikhel Change-Id: I3a0ca951b2c720be4e6fe2ed0e5d1830fcfb240c --- sim/src/image.rs | 102 ++++++++++++++++++++++++++++++++++++---------- sim/src/lib.rs | 5 ++- sim/src/tlv.rs | 12 +++++- sim/tests/core.rs | 20 ++++++--- 4 files changed, 109 insertions(+), 30 deletions(-) diff --git a/sim/src/image.rs b/sim/src/image.rs index 71f2d3c7..54e4f31b 100644 --- a/sim/src/image.rs +++ b/sim/src/image.rs @@ -123,6 +123,19 @@ struct SlotPlace { size: u32, } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ImageManipulation { + None, + BadSignature, + WrongOffset, + IgnoreRamLoadFlag, + /// True to use same address, + /// false to overlap by 1 byte + OverlapImages(bool), + CorruptHigherVersionImage, +} + + impl ImagesBuilder { /// Construct a new image builder for the given device. Returns /// Some(builder) if is possible to test this configuration, or None if @@ -210,22 +223,37 @@ impl ImagesBuilder { } /// Construct an `Images` that doesn't expect an upgrade to happen. - pub fn make_no_upgrade_image(self, deps: &DepTest) -> Images { + pub fn make_no_upgrade_image(self, deps: &DepTest, img_manipulation: ImageManipulation) -> Images { let num_images = self.num_images(); let mut flash = self.flash; - let ram = self.ram.clone(); // TODO: This is wasteful. + let ram = self.ram.clone(); // TODO: Avoid this clone. + let mut higher_version_corrupted = false; let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| { let dep: Box = if num_images > 1 { Box::new(PairDep::new(num_images, image_num, deps)) } else { Box::new(BoringDep::new(image_num, deps)) }; - let primaries = install_image(&mut flash, &slots[0], - maximal(42784), &ram, &*dep, false, Some(0)); - let upgrades = match deps.depends[image_num] { - DepType::NoUpgrade => install_no_image(), - _ => install_image(&mut flash, &slots[1], - maximal(46928), &ram, &*dep, false, Some(0)) + + let (primaries,upgrades) = if img_manipulation == ImageManipulation::CorruptHigherVersionImage && !higher_version_corrupted { + higher_version_corrupted = true; + let prim = install_image(&mut flash, &slots[0], + maximal(42784), &ram, &*dep, ImageManipulation::None, Some(0)); + let upgr = match deps.depends[image_num] { + DepType::NoUpgrade => install_no_image(), + _ => install_image(&mut flash, &slots[1], + maximal(46928), &ram, &*dep, ImageManipulation::BadSignature, Some(0)) + }; + (prim, upgr) + } else { + let prim = install_image(&mut flash, &slots[0], + maximal(42784), &ram, &*dep, img_manipulation, Some(0)); + let upgr = match deps.depends[image_num] { + DepType::NoUpgrade => install_no_image(), + _ => install_image(&mut flash, &slots[1], + maximal(46928), &ram, &*dep, img_manipulation, Some(0)) + }; + (prim, upgr) }; OneImage { slots, @@ -243,7 +271,7 @@ impl ImagesBuilder { } pub fn make_image(self, deps: &DepTest, permanent: bool) -> Images { - let mut images = self.make_no_upgrade_image(deps); + let mut images = self.make_no_upgrade_image(deps, ImageManipulation::None); for image in &images.images { mark_upgrade(&mut images.flash, &image.slots[1]); } @@ -274,9 +302,9 @@ impl ImagesBuilder { let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| { let dep = BoringDep::new(image_num, &NO_DEPS); let primaries = install_image(&mut bad_flash, &slots[0], - maximal(32784), &ram, &dep, false, Some(0)); + maximal(32784), &ram, &dep, ImageManipulation::None, Some(0)); let upgrades = install_image(&mut bad_flash, &slots[1], - maximal(41928), &ram, &dep, true, Some(0)); + maximal(41928), &ram, &dep, ImageManipulation::BadSignature, Some(0)); OneImage { slots, primaries, @@ -297,9 +325,9 @@ impl ImagesBuilder { let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| { let dep = BoringDep::new(image_num, &NO_DEPS); let primaries = install_image(&mut bad_flash, &slots[0], - maximal(32784), &ram, &dep, false, Some(0)); + maximal(32784), &ram, &dep, ImageManipulation::None, Some(0)); let upgrades = install_image(&mut bad_flash, &slots[1], - ImageSize::Oversized, &ram, &dep, false, Some(0)); + ImageSize::Oversized, &ram, &dep, ImageManipulation::None, Some(0)); OneImage { slots, primaries, @@ -320,7 +348,7 @@ impl ImagesBuilder { let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| { let dep = BoringDep::new(image_num, &NO_DEPS); let primaries = install_image(&mut flash, &slots[0], - maximal(32784), &ram, &dep, false, Some(0)); + maximal(32784), &ram, &dep,ImageManipulation::None, Some(0)); let upgrades = install_no_image(); OneImage { slots, @@ -343,7 +371,7 @@ impl ImagesBuilder { let dep = BoringDep::new(image_num, &NO_DEPS); let primaries = install_no_image(); let upgrades = install_image(&mut flash, &slots[1], - maximal(32784), &ram, &dep, false, Some(0)); + maximal(32784), &ram, &dep, ImageManipulation::None, Some(0)); OneImage { slots, primaries, @@ -365,7 +393,7 @@ impl ImagesBuilder { let dep = BoringDep::new(image_num, &NO_DEPS); let primaries = install_no_image(); let upgrades = install_image(&mut flash, &slots[1], - ImageSize::Oversized, &ram, &dep, false, Some(0)); + ImageSize::Oversized, &ram, &dep, ImageManipulation::None, Some(0)); OneImage { slots, primaries, @@ -387,9 +415,9 @@ impl ImagesBuilder { let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| { let dep = BoringDep::new(image_num, &NO_DEPS); let primaries = install_image(&mut flash, &slots[0], - maximal(32784), &ram, &dep, false, security_cnt); + maximal(32784), &ram, &dep, ImageManipulation::None, security_cnt); let upgrades = install_image(&mut flash, &slots[1], - maximal(41928), &ram, &dep, false, security_cnt.map(|v| v + 1)); + maximal(41928), &ram, &dep, ImageManipulation::None, security_cnt.map(|v| v + 1)); OneImage { slots, primaries, @@ -1318,6 +1346,28 @@ impl Images { false } + pub fn run_ram_load_boot_with_result(&self, expected_result: bool) -> bool { + if !Caps::RamLoad.present() { + return false; + } + // Clone the flash so we can tell if unchanged. + let mut flash = self.flash.clone(); + + // Create RAM config. + let ram = RamBlock::new(self.ram.total - RAM_LOAD_ADDR, RAM_LOAD_ADDR); + + // Run the bootloader, and verify that it couldn't run to completion. + let result = ram.invoke(|| c::boot_go(&mut flash, &self.areadesc, None, + None, true)); + + if result.success() != expected_result { + error!("RAM load boot result was not of the expected value! (was: {}, expected: {})", result.success(), expected_result); + return true; + } + + false + } + /// Adds a new flash area that fails statistically fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize, rate: f32) { @@ -1699,26 +1749,34 @@ fn image_largest_trailer(dev: &dyn Flash) -> usize { /// fields used by the given code. Returns a copy of the image that was written. fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: ImageSize, ram: &RamData, - deps: &dyn Depender, bad_sig: bool, security_counter:Option) -> ImageData { + deps: &dyn Depender, img_manipulation: ImageManipulation, security_counter:Option) -> ImageData { let offset = slot.base_off; let slot_len = slot.len; let dev_id = slot.dev_id; let dev = flash.get_mut(&dev_id).unwrap(); let mut tlv: Box = Box::new(make_tlv()); + if img_manipulation == ImageManipulation::IgnoreRamLoadFlag { + tlv.set_ignore_ram_load_flag(); + } tlv.set_security_counter(security_counter); + // Add the dependencies early to the tlv. for dep in deps.my_deps(offset, slot.index) { tlv.add_dependency(deps.other_id(), &dep); } const HDR_SIZE: usize = 32; - let place = ram.lookup(&slot); let load_addr = if Caps::RamLoad.present() { - place.offset + match img_manipulation { + ImageManipulation::WrongOffset => u32::MAX, + ImageManipulation::OverlapImages(true) => RAM_LOAD_ADDR, + ImageManipulation::OverlapImages(false) => place.offset - 1, + _ => place.offset + } } else { 0 }; @@ -1803,7 +1861,7 @@ fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: ImageSize, } // Build the TLV itself. - if bad_sig { + if img_manipulation == ImageManipulation::BadSignature { tlv.corrupt_sig(); } let mut b_tlv = tlv.make_tlv(); diff --git a/sim/src/lib.rs b/sim/src/lib.rs index df1919e0..fe43e46b 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) 2017-2019 Linaro LTD // Copyright (c) 2017-2019 JUUL Labs -// Copyright (c) 2019 Arm Limited +// Copyright (c) 2019-2023 Arm Limited // // SPDX-License-Identifier: Apache-2.0 @@ -30,6 +30,7 @@ pub use crate::{ image::{ ImagesBuilder, Images, + ImageManipulation, show_sizes, }, }; @@ -201,7 +202,7 @@ impl RunStatus { failed |= bad_secondary_slot_image.run_signfail_upgrade(); - let images = run.clone().make_no_upgrade_image(&NO_DEPS); + let images = run.clone().make_no_upgrade_image(&NO_DEPS, ImageManipulation::None); failed |= images.run_norevert_newimage(); let images = run.make_image(&NO_DEPS, true); diff --git a/sim/src/tlv.rs b/sim/src/tlv.rs index 99c02d96..5541f112 100644 --- a/sim/src/tlv.rs +++ b/sim/src/tlv.rs @@ -112,6 +112,10 @@ pub trait ManifestGen { /// Set the security counter to the specified value. fn set_security_counter(&mut self, security_cnt: Option); + + /// Sets the ignore_ram_load_flag so that can be validated when it is missing, + /// it will not load successfully. + fn set_ignore_ram_load_flag(&mut self); } #[derive(Debug, Default)] @@ -124,6 +128,8 @@ pub struct TlvGen { /// Should this signature be corrupted. gen_corrupted: bool, security_cnt: Option, + /// Ignore RAM_LOAD flag + ignore_ram_load_flag: bool, } #[derive(Debug)] @@ -318,7 +324,7 @@ impl ManifestGen for TlvGen { /// Retrieve the header flags for this configuration. This can be called at any time. fn get_flags(&self) -> u32 { // For the RamLoad case, add in the flag for this feature. - if Caps::RamLoad.present() { + if Caps::RamLoad.present() && !self.ignore_ram_load_flag { self.flags | (TlvFlags::RAM_LOAD as u32) } else { self.flags @@ -793,6 +799,10 @@ impl ManifestGen for TlvGen { fn set_security_counter(&mut self, security_cnt: Option) { self.security_cnt = security_cnt; } + + fn set_ignore_ram_load_flag(&mut self) { + self.ignore_ram_load_flag = true; + } } include!("rsa_pub_key-rs.txt"); diff --git a/sim/tests/core.rs b/sim/tests/core.rs index 45233de3..ee941fe1 100644 --- a/sim/tests/core.rs +++ b/sim/tests/core.rs @@ -1,6 +1,6 @@ // Copyright (c) 2017-2021 Linaro LTD // Copyright (c) 2017-2019 JUUL Labs -// Copyright (c) 2023 Arm Limited +// Copyright (c) 2021-2023 Arm Limited // // SPDX-License-Identifier: Apache-2.0 @@ -15,6 +15,7 @@ use bootsim::{ NO_DEPS, REV_DEPS, testlog, + ImageManipulation }; use std::{ env, @@ -51,7 +52,7 @@ sim_test!(bad_secondary_slot, make_bad_secondary_slot_image(), run_signfail_upgr sim_test!(secondary_trailer_leftover, make_erased_secondary_image(), run_secondary_leftover_trailer()); sim_test!(bootstrap, make_bootstrap_image(), run_bootstrap()); sim_test!(oversized_bootstrap, make_oversized_bootstrap_image(), run_oversized_bootstrap()); -sim_test!(norevert_newimage, make_no_upgrade_image(&NO_DEPS), run_norevert_newimage()); +sim_test!(norevert_newimage, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_norevert_newimage()); sim_test!(basic_revert, make_image(&NO_DEPS, true), run_basic_revert()); sim_test!(revert_with_fails, make_image(&NO_DEPS, false), run_revert_with_fails()); sim_test!(perm_with_fails, make_image(&NO_DEPS, true), run_perm_with_fails()); @@ -65,11 +66,20 @@ sim_test!(status_write_fails_complete, make_image(&NO_DEPS, true), run_with_stat sim_test!(status_write_fails_with_reset, make_image(&NO_DEPS, true), run_with_status_fails_with_reset()); sim_test!(downgrade_prevention, make_image(&REV_DEPS, true), run_nodowngrade()); -sim_test!(direct_xip_first, make_no_upgrade_image(&NO_DEPS), run_direct_xip()); -sim_test!(ram_load_first, make_no_upgrade_image(&NO_DEPS), run_ram_load()); -sim_test!(ram_load_split, make_no_upgrade_image(&NO_DEPS), run_split_ram_load()); +sim_test!(direct_xip_first, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_direct_xip()); +sim_test!(ram_load_first, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_ram_load()); +sim_test!(ram_load_split, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_split_ram_load()); sim_test!(hw_prot_failed_security_cnt_check, make_image_with_security_counter(Some(0)), run_hw_rollback_prot()); sim_test!(hw_prot_missing_security_cnt, make_image_with_security_counter(None), run_hw_rollback_prot()); +sim_test!(ram_load_out_of_bounds, make_no_upgrade_image(&NO_DEPS, ImageManipulation::WrongOffset), run_ram_load_boot_with_result(false)); +sim_test!(ram_load_missing_header_flag, make_no_upgrade_image(&NO_DEPS, ImageManipulation::IgnoreRamLoadFlag), run_ram_load_boot_with_result(false)); +sim_test!(ram_load_failed_validation, make_no_upgrade_image(&NO_DEPS, ImageManipulation::BadSignature), run_ram_load_boot_with_result(false)); +sim_test!(ram_load_corrupt_higher_version_image, make_no_upgrade_image(&NO_DEPS, ImageManipulation::CorruptHigherVersionImage), run_ram_load_boot_with_result(true)); + +#[cfg(feature = "multiimage")] +sim_test!(ram_load_overlapping_images_same_base, make_no_upgrade_image(&NO_DEPS, ImageManipulation::OverlapImages(true)), run_ram_load_boot_with_result(false)); +#[cfg(feature = "multiimage")] +sim_test!(ram_load_overlapping_images_offset, make_no_upgrade_image(&NO_DEPS, ImageManipulation::OverlapImages(false)), run_ram_load_boot_with_result(false)); // Test various combinations of incorrect dependencies. test_shell!(dependency_combos, r, {