Commit d6703520 authored by Roland Mikhel's avatar Roland Mikhel Committed by Dávid Vincze
Browse files

sim: Add hw-rollback-protection feature



This commit adds simulator support to test the
hw-rollback-protection feature which is using
nv-counters. In the simulator they are stored in Rust
to prevent any race conditions from happening due to
the parallel execution of the tests.

Signed-off-by: default avatarRoland Mikhel <roland.mikhel@arm.com>
Change-Id: I445fc50615ed1f0c06e5933b16811c24d9d302fc
parent 61962b94
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ ram-load = ["mcuboot-sys/ram-load"]
direct-xip = ["mcuboot-sys/direct-xip"]
downgrade-prevention = ["mcuboot-sys/downgrade-prevention"]
max-align-32 = ["mcuboot-sys/max-align-32"]
hw-rollback-protection = ["mcuboot-sys/hw-rollback-protection"]

[dependencies]
byteorder = "1.4"
+3 −0
Original line number Diff line number Diff line
@@ -83,6 +83,9 @@ downgrade-prevention = []
# Support images with 32-byte maximum write alignment value.
max-align-32 = []

# Enable hardware rollback protection
hw-rollback-protection = []

[build-dependencies]
cc = "1.0.25"

+6 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ fn main() {
    let ram_load = env::var("CARGO_FEATURE_RAM_LOAD").is_ok();
    let direct_xip = env::var("CARGO_FEATURE_DIRECT_XIP").is_ok();
    let max_align_32 = env::var("CARGO_FEATURE_MAX_ALIGN_32").is_ok();
    let hw_rollback_protection = env::var("CARGO_FEATURE_HW_ROLLBACK_PROTECTION").is_ok();

    let mut conf = CachedBuild::new();
    conf.conf.define("__BOOTSIM__", None);
@@ -75,6 +76,11 @@ fn main() {
        conf.conf.define("MCUBOOT_DIRECT_XIP", None);
    }

    if hw_rollback_protection {
        conf.conf.define("MCUBOOT_HW_ROLLBACK_PROT", None);
        conf.file("csupport/security_cnt.c");
    }

    // Currently no more than one sig type can be used simultaneously.
    if vec![sig_rsa, sig_rsa3072, sig_ecdsa, sig_ed25519].iter()
        .fold(0, |sum, &v| sum + v as i32) > 1 {
+43 −0
Original line number Diff line number Diff line
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2023 Arm Limited
 */

#include "bootutil/security_cnt.h"
#include "mcuboot_config/mcuboot_logging.h"
#include "bootutil/fault_injection_hardening.h"

/*
 * Since the simulator is executing unit tests in parallel,
 * the storage area where the security counter values reside
 * has to be managed per thread from Rust's side.
 */
#ifdef MCUBOOT_HW_ROLLBACK_PROT

int sim_set_nv_counter_for_image(uint32_t image_index, uint32_t security_counter_value);

int sim_get_nv_counter_for_image(uint32_t image_index, uint32_t* data);

fih_ret boot_nv_security_counter_init(void) {
    return FIH_SUCCESS;
}

fih_ret boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt) {
    uint32_t counter = 0;
    FIH_DECLARE(fih_rc, FIH_FAILURE);
    fih_rc = fih_ret_encode_zero_equality(sim_get_nv_counter_for_image(image_id, &counter));

    MCUBOOT_LOG_INF("Read security counter value (%d) for image: %d\n", counter, image_id);
    *security_cnt = fih_int_encode(counter);

    FIH_RET(fih_rc);
}

int32_t boot_nv_security_counter_update(uint32_t image_id, uint32_t img_security_cnt) {
    MCUBOOT_LOG_INF("Writing security counter value (%d) for image: %d\n", img_security_cnt, image_id);

    return sim_set_nv_counter_for_image(image_id, img_security_cnt);
}

#endif /* MCUBOOT_HW_ROLLBACK_PROT */
+59 −0
Original line number Diff line number Diff line
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2018-2019 JUUL Labs
// Copyright (c) 2023 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0

@@ -131,10 +132,32 @@ pub struct BootsimRamInfo {
    pub base: usize,
}

/// This struct stores the non-volatile security counter per image. It will be stored per test thread,
/// and the C code will set / get the values here.
#[repr(C)]
#[derive(Debug, Default)]
pub struct NvCounterStorage {
    pub storage: Vec<u32>,
}

impl NvCounterStorage {
    pub fn new() -> Self {
        let count = if cfg!(feature = "multiimage") {
            2
        } else {
            1
        };
        Self {
            storage: vec![0; count]
        }
    }
}

thread_local! {
    pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
    pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
    pub static RAM_CTX: RefCell<BootsimRamInfo> = RefCell::new(BootsimRamInfo::default());
    pub static NV_COUNTER_CTX: RefCell<NvCounterStorage> = RefCell::new(NvCounterStorage::new());
}

/// Set the flash device to be used by the simulation.  The pointer is unsafely stashed away.
@@ -317,3 +340,39 @@ pub extern fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
        0
    }
}

#[no_mangle]
pub extern "C" fn sim_set_nv_counter_for_image(image_index: u32, security_counter_value: u32) -> libc::c_int {
    let mut rc = 0;
    NV_COUNTER_CTX.with(|ctx| {
        let mut counter_storage = ctx.borrow_mut();
        if image_index as usize >= counter_storage.storage.len() {
            rc = -1;
            return;
        }
        if counter_storage.storage[image_index as usize] > security_counter_value {
            rc = -2;
            warn!("Failed to set security counter value ({}) for image index {}", security_counter_value, image_index);
            return;
        }

        counter_storage.storage[image_index as usize] = security_counter_value;
    });

    return rc;
}

#[no_mangle]
pub extern "C" fn sim_get_nv_counter_for_image(image_index: u32, security_counter_value: *mut u32) -> libc::c_int {
    let mut rc = 0;
    NV_COUNTER_CTX.with(|ctx| {
        let counter_storage = ctx.borrow();
        if image_index as usize >= counter_storage.storage.len() {
            rc = -1;
            return;
        }
        unsafe { *security_counter_value = counter_storage.storage[image_index as usize] };

    });
    return rc;
}
Loading