From 6e5a8cdf6d80167f55256ca8d80d302e361f2f1d Mon Sep 17 00:00:00 2001 From: Jean-Michel Picod Date: Fri, 11 Dec 2020 01:51:16 +0100 Subject: [PATCH] Add kernel support for firmware protection --- patches/tock/07-firmware-protect.patch | 350 +++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 patches/tock/07-firmware-protect.patch diff --git a/patches/tock/07-firmware-protect.patch b/patches/tock/07-firmware-protect.patch new file mode 100644 index 00000000..c0626487 --- /dev/null +++ b/patches/tock/07-firmware-protect.patch @@ -0,0 +1,350 @@ +diff --git a/boards/components/src/firmware_protection.rs b/boards/components/src/firmware_protection.rs +new file mode 100644 +index 0000000..5eda591 +--- /dev/null ++++ b/boards/components/src/firmware_protection.rs +@@ -0,0 +1,67 @@ ++//! Component for firmware protection syscall interface. ++//! ++//! This provides one Component, `FirmwareProtectionComponent`, which implements a ++//! userspace syscall interface to enable the code readout protection. ++//! ++//! Usage ++//! ----- ++//! ```rust ++//! let crp = components::firmware_protection::FirmwareProtectionComponent::new( ++//! board_kernel, ++//! nrf52840::uicr::Uicr::new() ++//! ) ++//! .finalize( ++//! components::firmware_protection_component_helper!(uicr)); ++//! ``` ++ ++use core::mem::MaybeUninit; ++ ++use capsules::firmware_protection; ++use kernel::capabilities; ++use kernel::component::Component; ++use kernel::create_capability; ++use kernel::hil; ++use kernel::static_init_half; ++ ++// Setup static space for the objects. ++#[macro_export] ++macro_rules! firmware_protection_component_helper { ++ ($C:ty) => {{ ++ use capsules::firmware_protection; ++ use core::mem::MaybeUninit; ++ static mut BUF: MaybeUninit> = MaybeUninit::uninit(); ++ &mut BUF ++ };}; ++} ++ ++pub struct FirmwareProtectionComponent { ++ board_kernel: &'static kernel::Kernel, ++ crp: C, ++} ++ ++impl FirmwareProtectionComponent { ++ pub fn new(board_kernel: &'static kernel::Kernel, crp: C) -> FirmwareProtectionComponent { ++ FirmwareProtectionComponent { ++ board_kernel: board_kernel, ++ crp: crp, ++ } ++ } ++} ++ ++impl Component for FirmwareProtectionComponent { ++ type StaticInput = &'static mut MaybeUninit>; ++ type Output = &'static firmware_protection::FirmwareProtection<'static, C>; ++ ++ unsafe fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output { ++ let grant_cap = create_capability!(capabilities::MemoryAllocationCapability); ++ ++ static_init_half!( ++ static_buffer, ++ firmware_protection::FirmwareProtection<'static, C>, ++ firmware_protection::FirmwareProtection::new( ++ self.crp, ++ self.board_kernel.create_grant(&grant_cap), ++ ) ++ ) ++ } ++} +diff --git a/boards/components/src/lib.rs b/boards/components/src/lib.rs +index 917497a..520408f 100644 +--- a/boards/components/src/lib.rs ++++ b/boards/components/src/lib.rs +@@ -9,6 +9,7 @@ pub mod console; + pub mod crc; + pub mod debug_queue; + pub mod debug_writer; ++pub mod firmware_protection; + pub mod ft6x06; + pub mod gpio; + pub mod hd44780; +diff --git a/boards/nordic/nrf52840_dongle/src/main.rs b/boards/nordic/nrf52840_dongle/src/main.rs +index 118ea6d..f340dd1 100644 +--- a/boards/nordic/nrf52840_dongle/src/main.rs ++++ b/boards/nordic/nrf52840_dongle/src/main.rs +@@ -112,6 +112,10 @@ pub struct Platform { + 'static, + nrf52840::usbd::Usbd<'static>, + >, ++ crp: &'static capsules::firmware_protection::FirmwareProtection< ++ 'static, ++ nrf52840::uicr::Uicr, ++ >, + } + + impl kernel::Platform for Platform { +@@ -132,6 +136,7 @@ impl kernel::Platform for Platform { + capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)), + nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)), + capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)), ++ capsules::firmware_protection::DRIVER_NUM => f(Some(self.crp)), + kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), + _ => f(None), + } +@@ -355,6 +360,12 @@ pub unsafe fn reset_handler() { + ) + .finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd)); + ++ let crp = components::firmware_protection::FirmwareProtectionComponent::new( ++ board_kernel, ++ nrf52840::uicr::Uicr::new(), ++ ) ++ .finalize(components::firmware_protection_component_helper!(nrf52840::uicr::Uicr)); ++ + nrf52_components::NrfClockComponent::new().finalize(()); + + let platform = Platform { +@@ -371,6 +382,7 @@ pub unsafe fn reset_handler() { + analog_comparator, + nvmc, + usb, ++ crp, + ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability), + }; + +diff --git a/boards/nordic/nrf52840dk/src/main.rs b/boards/nordic/nrf52840dk/src/main.rs +index b1d0d3c..a37d180 100644 +--- a/boards/nordic/nrf52840dk/src/main.rs ++++ b/boards/nordic/nrf52840dk/src/main.rs +@@ -180,6 +180,10 @@ pub struct Platform { + 'static, + nrf52840::usbd::Usbd<'static>, + >, ++ crp: &'static capsules::firmware_protection::FirmwareProtection< ++ 'static, ++ nrf52840::uicr::Uicr, ++ >, + } + + impl kernel::Platform for Platform { +@@ -201,6 +205,7 @@ impl kernel::Platform for Platform { + capsules::nonvolatile_storage_driver::DRIVER_NUM => f(Some(self.nonvolatile_storage)), + nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)), + capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)), ++ capsules::firmware_protection::DRIVER_NUM => f(Some(self.crp)), + kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), + _ => f(None), + } +@@ -480,6 +485,12 @@ pub unsafe fn reset_handler() { + ) + .finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd)); + ++ let crp = components::firmware_protection::FirmwareProtectionComponent::new( ++ board_kernel, ++ nrf52840::uicr::Uicr::new(), ++ ) ++ .finalize(components::firmware_protection_component_helper!(nrf52840::uicr::Uicr)); ++ + nrf52_components::NrfClockComponent::new().finalize(()); + + let platform = Platform { +@@ -497,6 +508,7 @@ pub unsafe fn reset_handler() { + nonvolatile_storage, + nvmc, + usb, ++ crp, + ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability), + }; + +diff --git a/capsules/src/driver.rs b/capsules/src/driver.rs +index ae458b3..f536dad 100644 +--- a/capsules/src/driver.rs ++++ b/capsules/src/driver.rs +@@ -16,6 +16,7 @@ pub enum NUM { + Adc = 0x00005, + Dac = 0x00006, + AnalogComparator = 0x00007, ++ FirmwareProtection = 0x00008, + + // Kernel + Ipc = 0x10000, +diff --git a/capsules/src/firmware_protection.rs b/capsules/src/firmware_protection.rs +new file mode 100644 +index 0000000..2c61d06 +--- /dev/null ++++ b/capsules/src/firmware_protection.rs +@@ -0,0 +1,87 @@ ++//! Provides userspace control of firmware protection on a board. ++//! ++//! This allows an application to enable firware readout protection, ++//! disabling JTAG interface and other ways to read/tamper the firmware. ++//! Of course, outside of a hardware bug, once set, the only way to enable ++//! programming/debugging is by fully erasing the flash. ++//! ++//! Usage ++//! ----- ++//! ++//! ```rust ++//! # use kernel::static_init; ++//! ++//! let crp = static_init!( ++//! capsules::firware_protection::FirmwareProtection<'static>, ++//! capsules::firware_protection::FirmwareProtection::new( ++//! nrf52840::uicr::Uicr, ++//! board_kernel.create_grant(&grant_cap), ++//! ); ++//! ``` ++//! ++//! Syscall Interface ++//! ----------------- ++//! ++//! - Stability: 2 - Stable ++//! ++//! ### Command ++//! ++//! Enable code readout protection on the current board. ++//! ++//! #### `command_num` ++//! ++//! - `0`: Driver check. ++//! - `1`: Enable firmware readout protection (aka CRP). ++//! ++ ++use core::marker::PhantomData; ++use kernel::hil; ++use kernel::{AppId, Callback, Driver, Grant, ReturnCode}; ++ ++/// Syscall driver number. ++use crate::driver; ++pub const DRIVER_NUM: usize = driver::NUM::FirmwareProtection as usize; ++ ++pub struct FirmwareProtection<'a, C: hil::firmware_protection::FirmwareProtection> { ++ crp_unit: C, ++ apps: Grant>, ++ _phantom: PhantomData<&'a C>, ++} ++ ++impl<'a, C: hil::firmware_protection::FirmwareProtection> FirmwareProtection<'a, C> { ++ pub fn new( ++ crp_unit: C, ++ apps: Grant>, ++ ) -> Self { ++ Self { ++ crp_unit, ++ apps, ++ _phantom: PhantomData, ++ } ++ } ++} ++ ++impl<'a, C: hil::firmware_protection::FirmwareProtection> Driver for FirmwareProtection<'a, C> { ++ /// ++ /// ### Command numbers ++ /// ++ /// * `0`: Returns non-zero to indicate the driver is present. ++ /// * `1`: Enable firmware protection. ++ fn command(&self, command_num: usize, _: usize, _: usize, appid: AppId) -> ReturnCode { ++ match command_num { ++ // return if driver is available ++ 0 => ReturnCode::SUCCESS, ++ ++ // enable firmware protection ++ 1 => { ++ self.apps.enter(appid, |_, _| { ++ self.crp_unit.protect() ++ }) ++ .unwrap_or_else(|err| err.into()) ++ } ++ ++ // default ++ _ => ReturnCode::ENOSUPPORT, ++ } ++ } ++} +diff --git a/capsules/src/lib.rs b/capsules/src/lib.rs +index e4423fe..7538aad 100644 +--- a/capsules/src/lib.rs ++++ b/capsules/src/lib.rs +@@ -22,6 +22,7 @@ pub mod crc; + pub mod dac; + pub mod debug_process_restart; + pub mod driver; ++pub mod firmware_protection; + pub mod fm25cl; + pub mod ft6x06; + pub mod fxos8700cq; +diff --git a/chips/nrf52/src/uicr.rs b/chips/nrf52/src/uicr.rs +index 3bb8b5a..b8895d3 100644 +--- a/chips/nrf52/src/uicr.rs ++++ b/chips/nrf52/src/uicr.rs +@@ -8,6 +8,7 @@ use kernel::hil; + use kernel::ReturnCode; + + use crate::gpio::Pin; ++use crate::nvmc::NVMC; + + const UICR_BASE: StaticRef = + unsafe { StaticRef::new(0x10001000 as *const UicrRegisters) }; +@@ -210,3 +211,20 @@ impl Uicr { + self.registers.approtect.write(ApProtect::PALL::ENABLED); + } + } ++ ++impl hil::firmware_protection::FirmwareProtection for Uicr { ++ fn protect(&self) -> ReturnCode { ++ unsafe { NVMC.configure_writeable() }; ++ self.set_ap_protect(); ++ // Prevent CPU debug ++ self.registers.debugctrl.write( ++ DebugControl::CPUNIDEN::DISABLED + DebugControl::CPUFPBEN::DISABLED); ++ // TODO(jmichel): Kill bootloader if present ++ unsafe { NVMC.configure_readonly() }; ++ if self.is_ap_protect_enabled() { ++ ReturnCode::SUCCESS ++ } else { ++ ReturnCode::FAIL ++ } ++ } ++} +diff --git a/kernel/src/hil/firmware_protection.rs b/kernel/src/hil/firmware_protection.rs +new file mode 100644 +index 0000000..e43fdf0 +--- /dev/null ++++ b/kernel/src/hil/firmware_protection.rs +@@ -0,0 +1,8 @@ ++//! Interface for Firmware Protection, also called Code Readout Protection. ++ ++use crate::returncode::ReturnCode; ++ ++pub trait FirmwareProtection { ++ /// Disable debug ports and protects the device. ++ fn protect(&self) -> ReturnCode; ++} +diff --git a/kernel/src/hil/mod.rs b/kernel/src/hil/mod.rs +index 4f42afa..83e7702 100644 +--- a/kernel/src/hil/mod.rs ++++ b/kernel/src/hil/mod.rs +@@ -8,6 +8,7 @@ pub mod dac; + pub mod digest; + pub mod eic; + pub mod entropy; ++pub mod firmware_protection; + pub mod flash; + pub mod gpio; + pub mod gpio_async; +