Struct EarlGreyEPMP

Source
pub struct EarlGreyEPMP<const HANDOVER_CONFIG_CHECK: bool, DBG: EPMPDebugConfig> { /* private fields */ }
Expand description

RISC-V ePMP memory protection implementation for the EarlGrey SoC.

The EarlGrey ePMP implementation hard-codes many assumptions about the behavior and state of the underlying hardware, to reduce complexity of this codebase, and improve its security, reliability and auditability.

Namely, it makes and checks assumptions about the machine security policy prior to its initialization routine, locks down the hardware through a static set of PMP configuration steps, and then exposes a subset of regions for user-mode protection through the PMPUserMPU trait.

The EarlGrey ePMP implementation supports JTAG debug-port access through the integrated RISC-V Debug Manger (RVDM) core, which requires R/W/X-access to a given region of memory in machine-mode and user-mode. The EarlGreyEPMP struct accepts a generic EPMPDebugConfig implementation, which either enables (in the case of EPMPDebugEnable) or disables (EPMPDebugDisable) the debug-port access. However, enabling debug-port access can potentially weaken the system’s security by not enabling machine-mode lockdown (MML), and uses an additional PMP region otherwise available to userspace. See the documentation of EPMPDebugConfig for more information on this.

§ePMP Region Layout & Configuration (EPMPDebugDisable mode)

Because of the machine-mode lockdown (MML) mode, no region can have R/W/X permissions. The machine-mode whitelist policy (MMWP) further requires all memory accessed by machine-mode to have a corresponding locked PMP entry defined. Lower-indexed PMP entires have precedence over entries with higher indices. Under MML mode, a non-locked (user-mode) entry prevents machine-mode access to that memory. Thus, the ePMP is to be configured in a “sandwiched” layout (with decreasing precedence):

  1. High-priority machine-mode “lockdown” entries.

    These entries are only accessible to machine mode. Once locked, they can only be changed through a hart reset. Examples for such memory sections can be the kernel’s .text or certain RAM (e.g. stack) sections.

  2. Tock’s user-mode “MPU”

    This section defines entries corresponding to memory sections made accessible to user-mode. These entires are exposed through the implementation of the TORUserPMP trait.

    Effectively, this is Tock’s “MPU” sandwiched in between the high-priority and low-priority PMP sections.

    These entires are not locked and must be turned off prior to the kernel being able to access them.

    This section must take precende over the lower kernel-mode entries, as these entries are aliased by the lower kernel-mode entries. Having a locked machine-mode entry take precende over an alias a user-space one prevents user-mode from accessing the aliased memory.

  3. Low-priority machine-mode “accessability” entires.

    These entires provide the kernel access to memory regions which are (partially) aliased by user-mode regions above. This allows for implementing memory sharing between userspace and the kernel (moving acccess to user-mode by turning on a region above, and falling back onto these rules when turning the user-mode region off).

    These regions can be granular (e.g. grant R/W on the entire RAM), but should not provide any excess permissions where not required (e.g. avoid granting R/X on flash-memory where only R is required, because the kernel-text is already marked as R/X in the high-priority regions above.

Because the ROM_EXT and test ROM set up different ePMP configs, there are separate initialization routines (new and new_test_rom) for those environments.

new (only available when the debug-port is disabled) attempts to set up the following memory protection rules and layout:

  • msseccfg CSR:

    |-----+-----------------------------------------------------------+-------|
    | BIT | LABEL                                                     | STATE |
    |-----+-----------------------------------------------------------+-------|
    |   0 | Machine-Mode Lockdown (MML)                               |     1 |
    |   1 | Machine-Mode Whitelist Policy (MMWP)                      |     1 |
    |   2 | Rule-Lock Bypass (RLB)                                    |     0 |
    |-----+-----------------------------------------------------------+-------|
  • pmpcfgX / pmpaddrX CSRs:

    |-------+----------------------------------------+-----------+---+-------|
    | ENTRY | REGION / ADDR                          | MODE      | L | PERMS |
    |-------+----------------------------------------+-----------+---+-------|
    |     0 | Locked by the ROM_EXT or unused        | NAPOT/OFF | X |       |
    |       |                                        |           |   |       |
    |     1 | Locked by the ROM_EXT or unused        | NAPOT/OFF | X |       |
    |       |                                        |           |   |       |
    |     2 | -------------------------------------- | OFF       | X | ----- |
    |     3 | Kernel .text section                   | TOR       | X | R/X   |
    |       |                                        |           |   |       |
    |     4 | /                                    \ | OFF       |   |       |
    |     5 | \ Userspace TOR region #0            / | TOR       |   | ????? |
    |       |                                        |           |   |       |
    |     6 | /                                    \ | OFF       |   |       |
    |     7 | \ Userspace TOR region #1            / | TOR       |   | ????? |
    |       |                                        |           |   |       |
    |     8 | /                                    \ | OFF       |   |       |
    |     9 | \ Userspace TOR region #2            / | TOR       |   | ????? |
    |       |                                        |           |   |       |
    |    10 | /                                    \ | OFF       |   |       |
    |    11 | \ Userspace TOR region #3            / | TOR       |   | ????? |
    |       |                                        |           |   |       |
    |    12 | FLASH (spanning kernel & apps)         | NAPOT     | X | R     |
    |       |                                        |           |   |       |
    |    13 | -------------------------------------- | OFF       | X | ----- |
    |       |                                        |           |   |       |
    |    14 | RAM (spanning kernel & apps)           | NAPOT     | X | R/W   |
    |       |                                        |           |   |       |
    |    15 | MMIO                                   | NAPOT     | X | R/W   |
    |-------+----------------------------------------+-----------+---+-------|

new_test_rom (only available when the debug-port is disabled) attempts to set up the following memory protection rules and layout:

  • msseccfg CSR:

    |-----+-----------------------------------------------------------+-------|
    | BIT | LABEL                                                     | STATE |
    |-----+-----------------------------------------------------------+-------|
    |   0 | Machine-Mode Lockdown (MML)                               |     1 |
    |   1 | Machine-Mode Whitelist Policy (MMWP)                      |     1 |
    |   2 | Rule-Lock Bypass (RLB)                                    |     0 |
    |-----+-----------------------------------------------------------+-------|
  • pmpcfgX / pmpaddrX CSRs:

    |-------+---------------------------------------------+-------+---+-------|
    | ENTRY | REGION / ADDR                               | MODE  | L | PERMS |
    |-------+---------------------------------------------+-------+---+-------|
    |     0 | ------------------------------------------- | OFF   | X | ----- |
    |     1 | Kernel .text section                        | TOR   | X | R/X   |
    |       |                                             |       |   |       |
    |     2 | ------------------------------------------- | OFF   | X |       |
    |       |                                             |       |   |       |
    |     3 | ------------------------------------------- | OFF   | X |       |
    |       |                                             |       |   |       |
    |     4 | /                                         \ | OFF   |   |       |
    |     5 | \ Userspace TOR region #0                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |     6 | /                                         \ | OFF   |   |       |
    |     7 | \ Userspace TOR region #1                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |     8 | /                                         \ | OFF   |   |       |
    |     9 | \ Userspace TOR region #2                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |    10 | /                                         \ | OFF   |   |       |
    |    11 | \ Userspace TOR region #3                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |    12 | ------------------------------------------- | OFF   | X | ----- |
    |       |                                             |       |   |       |
    |    13 | FLASH (spanning kernel & apps)              | NAPOT | X | R     |
    |       |                                             |       |   |       |
    |    14 | RAM (spanning kernel & apps)                | NAPOT | X | R/W   |
    |       |                                             |       |   |       |
    |    15 | MMIO                                        | NAPOT | X | R/W   |
    |-------+---------------------------------------------+-------+---+-------|

§ePMP Region Layout & Configuration (EPMPDebugEnable mode)

When enabling the RISC-V Debug Manager (JTAG debug port), the ePMP must be configured differently. This is because the RVDM requires a memory section to be mapped with read-write-execute privileges, which is not possible under the machine-mode lockdown (MML) mode. However, when simply disabling MML in the above policy, it would grant userspace access to kernel memory through the locked PMP entires. We still need to define locked PMP entries to grant the kernel (machine-mode) access to its required memory regions, as the machine-mode whitelist policy (MMWP) is enabled.

Thus we split the PMP entires into three parts, as outlined in the following:

  1. Tock’s user-mode “MPU”

    This section defines entries corresponding to memory sections made accessible to user-mode. These entires are exposed through the implementation of the TORUserPMP trait.

    These entires are not locked. Because the machine-mode lockdown (MML) mode is not enabled, non-locked regions are ignored in machine-mode. The kernel does not have to disable these entires prior to being able to access them.

    This section must take precende over the lower kernel-mode entries, as these entries are aliased by the lower kernel-mode entries. Having a locked machine-mode entry take precende over an alias a user-space one prevents user-mode from accessing the aliased memory.

  2. User-mode “deny-all” rule.

    Without machine-mode lockdown (MML) mode, locked regions apply to both user- and kernel-mode. Because the machine-mode whitelist policy (MMWP) is enabled, the kernel must be granted explicit permission to access memory (default-deny policy). This means that we must prevent any user-mode access from “falling through” to kernel-mode regions. For this purpose, we insert a non-locked “deny-all” rule which disallows all user-mode accesses to the entire address space, if no other higher-priority user-mode rule matches.

  3. Machine-mode “accessability” entires.

    These entires provide the kernel access to certain memory regions, as required by the machine-mode whitelist policy (MMWP).

new_debug (only available when the debug-port is enabled) attempts to set up the following memory protection rules and layout:

  • msseccfg CSR:

    |-----+-----------------------------------------------------------+-------|
    | BIT | LABEL                                                     | STATE |
    |-----+-----------------------------------------------------------+-------|
    |   0 | Machine-Mode Lockdown (MML)                               |     0 |
    |   1 | Machine-Mode Whitelist Policy (MMWP)                      |     1 |
    |   2 | Rule-Lock Bypass (RLB)                                    |     0 |
    |-----+-----------------------------------------------------------+-------|
  • pmpcfgX / pmpaddrX CSRs:

    |-------+---------------------------------------------+-------+---+-------|
    | ENTRY | REGION / ADDR                               | MODE  | L | PERMS |
    |-------+---------------------------------------------+-------+---+-------|
    |     0 | /                                         \ | OFF   |   |       |
    |     1 | \ Userspace TOR region #0                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |     2 | /                                         \ | OFF   |   |       |
    |     3 | \ Userspace TOR region #1                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |     4 | /                                         \ | OFF   |   |       |
    |     5 | \ Userspace TOR region #2                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |     6 | /                                         \ | OFF   |   |       |
    |     7 | \ Userspace TOR region #3                 / | TOR   |   | ????? |
    |       |                                             |       |   |       |
    |     8 | ------------------------------------------- | OFF   |   | ----- |
    |       |                                             |       |   |       |
    |     9 | "Deny-all" user-mode rule (all memory)      | NAPOT |   | ----- |
    |       |                                             |       |   |       |
    |    10 | ------------------------------------------- | OFF   | X | ----- |
    |    11 | Kernel .text section                        | TOR   | X | R/X   |
    |       |                                             |       |   |       |
    |    12 | RVDM Debug Core Memory                      | NAPOT | X | R/W/X |
    |       |                                             |       |   |       |
    |    13 | FLASH (spanning kernel & apps)              | NAPOT | X | R     |
    |       |                                             |       |   |       |
    |    14 | RAM (spanning kernel & apps)                | NAPOT | X | R/W   |
    |       |                                             |       |   |       |
    |    15 | MMIO                                        | NAPOT | X | R/W   |
    |-------+---------------------------------------------+-------+---+-------|

Implementations§

Source§

impl<const HANDOVER_CONFIG_CHECK: bool> EarlGreyEPMP<HANDOVER_CONFIG_CHECK, EPMPDebugDisable>

Source

pub unsafe fn new( flash: FlashRegion, ram: RAMRegion, mmio: MMIORegion, kernel_text: KernelTextRegion, ) -> Result<Self, EarlGreyEPMPError>

Source

pub unsafe fn new_test_rom( flash: FlashRegion, ram: RAMRegion, mmio: MMIORegion, kernel_text: KernelTextRegion, ) -> Result<Self, EarlGreyEPMPError>

Source§

impl<const HANDOVER_CONFIG_CHECK: bool> EarlGreyEPMP<HANDOVER_CONFIG_CHECK, EPMPDebugEnable>

Source

pub unsafe fn new_debug( flash: FlashRegion, ram: RAMRegion, mmio: MMIORegion, kernel_text: KernelTextRegion, debug_memory: RVDMRegion, ) -> Result<Self, EarlGreyEPMPError>

Trait Implementations§

Source§

impl<const HANDOVER_CONFIG_CHECK: bool, DBG: EPMPDebugConfig> Display for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, DBG>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<const HANDOVER_CONFIG_CHECK: bool> TORUserPMP<{ TOR_USER_REGIONS_DEBUG_DISABLE }> for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, EPMPDebugDisable>

Source§

const CONST_ASSERT_CHECK: () = ()

A placeholder to define const-assertions which are evaluated in PMPUserMPU::new. This can be used to, for instance, assert that the number of userspace regions does not exceed the number of hardware regions.
Source§

fn available_regions(&self) -> usize

The number of TOR regions currently available for userspace memory protection. Within [0; MAX_REGIONS]. Read more
Source§

fn configure_pmp( &self, regions: &[(TORUserPMPCFG, *const u8, *const u8); 4], ) -> Result<(), ()>

Configure the user-mode memory protection. Read more
Source§

fn enable_user_pmp(&self) -> Result<(), ()>

Enable the user-mode memory protection. Read more
Source§

fn disable_user_pmp(&self)

Disable the user-mode memory protection. Read more
Source§

impl<const HANDOVER_CONFIG_CHECK: bool> TORUserPMP<{ TOR_USER_REGIONS_DEBUG_ENABLE }> for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, EPMPDebugEnable>

Source§

const CONST_ASSERT_CHECK: () = ()

A placeholder to define const-assertions which are evaluated in PMPUserMPU::new. This can be used to, for instance, assert that the number of userspace regions does not exceed the number of hardware regions.
Source§

fn available_regions(&self) -> usize

The number of TOR regions currently available for userspace memory protection. Within [0; MAX_REGIONS]. Read more
Source§

fn configure_pmp( &self, regions: &[(TORUserPMPCFG, *const u8, *const u8); 4], ) -> Result<(), ()>

Configure the user-mode memory protection. Read more
Source§

fn enable_user_pmp(&self) -> Result<(), ()>

Enable the user-mode memory protection. Read more
Source§

fn disable_user_pmp(&self)

Disable the user-mode memory protection. Read more

Auto Trait Implementations§

§

impl<const HANDOVER_CONFIG_CHECK: bool, DBG> !Freeze for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, DBG>

§

impl<const HANDOVER_CONFIG_CHECK: bool, DBG> !RefUnwindSafe for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, DBG>

§

impl<const HANDOVER_CONFIG_CHECK: bool, DBG> Send for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, DBG>
where DBG: Send,

§

impl<const HANDOVER_CONFIG_CHECK: bool, DBG> !Sync for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, DBG>

§

impl<const HANDOVER_CONFIG_CHECK: bool, DBG> Unpin for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, DBG>
where DBG: Unpin,

§

impl<const HANDOVER_CONFIG_CHECK: bool, DBG> UnwindSafe for EarlGreyEPMP<HANDOVER_CONFIG_CHECK, DBG>
where DBG: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.