Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 120 additions & 5 deletions spec/std/isa/csr/mseccfg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,124 @@ long_name: Machine Security Configuration
address: 0x747
writable: true
priv_mode: M
length: 64
description: Machine Security Configuration
length: MXLEN
description: Machine Security Configuration register is used for configuring various security mechanisms present on the hart.
definedBy:
name: Sm
version: ">= 1.12"
fields: {}
name: Smepmp
version: ~> 1.0.0
fields:
MML:
location: 0
definedBy: Smepmp
description: |
Machine Mode Lockdown (mseccfg.MML) is a sticky bit, meaning that once set it cannot be unset until a PMP reset. When `mseccfg.MML` is set
the system's behavior changes in the following way:

a. The meaning of `pmpcfg.L` changes: Instead of marking a rule as locked and enforced in all modes, it now marks a rule as M-mode-only
when set and S/U-mode-only when unset. The formerly reserved encoding of `pmpcfg.RW=01`, and the encoding `pmpcfg.LRWX=1111`, now encode
a Shared-Region.

An M-mode-only rule is enforced on Machine mode and denied in Supervisor or User mode. It also remains locked so that any further
modifications to its associated configuration or address registers are ignored until a PMP reset, unless `mseccfg.RLB` is set.

An S/U-mode-only rule is enforced on Supervisor and User modes and denied on Machine mode.

A Shared-Region rule is enforced on all modes, with restrictions depending on the `pmpcfg.L` and `pmpcfg.X` bits:

- A Shared-Region rule where `pmpcfg.L` is not set can be used for sharing data between M-mode and S/U-mode, so is not executable. M-mode
has read/write access to that region, and S/U-mode has read access if `pmpcfg.X` is not set, or read/write access if `pmpcfg.X` is set.

- A Shared-Region rule where `pmpcfg.L` is set can be used for sharing code between M-mode and S/U-mode, so is not writable. Both M-mode and
S/U-mode have execute access on the region, and M-mode also has read access if `pmpcfg.X` is set. The rule remains locked so that any further
modifications to its associated configuration or address registers are ignored until a PMP reset, unless `mseccfg.RLB` is set.

- The encoding `pmpcfg.LRWX=1111` can be used for sharing data between M-mode and S/U mode, where both modes only have read-only access to the
region. The rule remains locked so that any further modifications to its associated configuration or address registers are ignored until a PMP
reset, unless `mseccfg.RLB` is set.

b. Adding a rule with executable privileges that either is M-mode-only or a locked Shared-Region is not possible and such pmpcfg writes are ignored,
leaving pmpcfg unchanged. This restriction can be temporarily lifted by setting `mseccfg.RLB` e.g. during the boot process.

c. Executing code with Machine mode privileges is only possible from memory regions with a matching M-mode-only rule or a locked Shared-Region rule
with executable privileges. Executing code from a region without a matching rule or with a matching S/U-mode-only rule is denied.

d. If mseccfg.MML is not set, the combination of `pmpcfg.RW=01` remains reserved for future standard use.

The truth table when the `mseccfg.MML` is set:

[cols="4*^.^1,2*^.^3", separator="!", %autowidth, options="header"]
!====
4+^! Bits on _pmpcfg_ register 2+^! Result
! L ! R ! W ! X ! M Mode ! S/U Mode

! 0 ! 0 ! 0 ! 0 2+^! Inaccessible region (Access Exception)
! 0 ! 0 ! 0 ! 1 ! Access Exception ! Execute-only region
! 0 ! 0 ! 1 ! 0 2+^! Shared data region: Read/write on M mode, Read-only on S/U mode
! 0 ! 0 ! 1 ! 1 2+^! Shared data region: Read/write for both M and S/U mode
! 0 ! 1 ! 0 ! 0 ! Access Exception ! Read-only region
! 0 ! 1 ! 0 ! 1 ! Access Exception ! Read/Execute region
! 0 ! 1 ! 1 ! 0 ! Access Exception ! Read/Write region
! 0 ! 1 ! 1 ! 1 ! Access Exception ! Read/Write/Execute region
! 1 ! 0 ! 0 ! 0 2+^! Locked inaccessible region* (Access Exception)
! 1 ! 0 ! 0 ! 1 ! Locked Execute-only region* ! Access Exception
! 1 ! 0 ! 1 ! 0 2+^! Locked Shared code region: Execute only on both M and S/U mode.*
! 1 ! 0 ! 1 ! 1 2+^! Locked Shared code region: Execute only on S/U mode, read/execute on M mode.*
! 1 ! 1 ! 0 ! 0 ! Locked Read-only region* ! Access Exception
! 1 ! 1 ! 0 ! 1 ! Locked Read/Execute region* ! Access Exception
! 1 ! 1 ! 1 ! 0 ! Locked Read/Write region* ! Access Exception
! 1 ! 1 ! 1 ! 1 2+^! Locked Shared data region: Read only on both M and S/U mode.*
!====

*Locked rules cannot be removed or modified until a PMP reset, unless mseccfg.RLB is set.
type(): |
if ((MSECCFG_MML_TYPE == "read-only-0") || (MSECCFG_MML_TYPE == "read-only-1")) {
return CsrFieldType::RO;
} else if (MSECCFG_MML_TYPE == "sticky") {
# Restricted: 0→1 allowed, 1→0 not allowed
return CsrFieldType::RWR;
}
sw_write(csr_value): |
return csr_value.MML | CSR[mseccfg].MML;
reset_value(): |
if ((MSECCFG_MML_TYPE == "read-only-0") || (MSECCFG_MML_TYPE == "sticky")) {
return 0;
} else if (MSECCFG_MML_TYPE == "read-only-1") {
return 1;
}
return UNDEFINED_LEGAL;
MMWP:
location: 1
definedBy: Smepmp
description: |
Machine-Mode Allowlist Policy (mseccfg.MMWP) is a sticky bit, meaning that once set it cannot be unset until a PMP reset. When set it
changes the default PMP policy for M-mode when accessing memory regions that don't have a matching PMP rule, to denied instead of ignored.
type(): |
if ((MSECCFG_MMWP_TYPE == "read-only-0") || (MSECCFG_MMWP_TYPE == "read-only-1")) {
return CsrFieldType::RO;
} else if (MSECCFG_MMWP_TYPE == "sticky") {
# Restricted: 0→1 allowed, 1→0 not allowed
return CsrFieldType::RWR;
}
sw_write(csr_value): |
return csr_value.MMWP | CSR[mseccfg].MMWP;
reset_value(): |
if ((MSECCFG_MMWP_TYPE == "read-only-0") || (MSECCFG_MMWP_TYPE == "sticky")) {
return 0;
} else if (MSECCFG_MMWP_TYPE == "read-only-1") {
return 1;
}
return UNDEFINED_LEGAL;
RLB:
location: 2
description: |
Rule Locking Bypass (mseccfg.RLB) bit has the following functionality:

a. When `mseccfg.RLB` is 1 locked PMP rules may be removed/modified and locked PMP entries may be edited.

b. When `mseccfg.RLB` is 0 and `pmpcfg.L` is 1 in any rule or entry (including disabled entries), then
remains 0 and any further modifications to `mseccfg.RLB` are ignored until a PMP reset.
type(): |
return MUTABLE_MSECCFG_RLB ? CsrFieldType::RW : CsrFieldType::RO;
definedBy: Smepmp
reset_value(): |
return MUTABLE_MSECCFG_RLB ? 0 : UNDEFINED_LEGAL;
7 changes: 4 additions & 3 deletions spec/std/isa/csr/mseccfgh.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ address: 0x757
writable: true
priv_mode: M
length: 32
description: Machine Security Configuration
description: |
The `mseccfgh` is a 32-bit read/write register that aliases bits 63:32 of `mseccfg`.
definedBy:
name: Sm
version: ">= 1.12"
name: Smepmp
version: ~> 1.0.0
fields: {}
184 changes: 184 additions & 0 deletions spec/std/isa/ext/Smepmp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause-Clear

# yaml-language-server: $schema=../../../schemas/ext_schema.json

$schema: "ext_schema.json#"
kind: extension
name: Smepmp
type: privileged
long_name: PMP Enhancements for memory access and execution prevention in Machine mode
versions:
- version: "1.0.0"
state: ratified
ratification_date: 2021-12
contributors:
- name: Nick Kossifidis
- name: Joe Xie
- name: Bill Huffman
- name: Allen Baum
- name: Greg Favor
- name: Tariq Kurd
- name: Fumio Arakawa
- name: RISC-V TEE Task Group

description: |
Being able to access the memory of a process running at a high privileged execution mode, such as the
Supervisor or Machine mode, from a lower privileged mode such as the User mode, introduces an obvious
attack vector since it allows for an attacker to perform privilege escalation, and tamper with the code
and/or data of that process. A less obvious attack vector exists when the reverse happens, in which case
an attacker instead of tampering with code and/or data that belong to a high-privileged process, can
tamper with the memory of an unprivileged / less-privileged process and trick the high-privileged process
to use or execute it.

To prevent this attack vector, two mechanisms known as Supervisor Memory Access Prevention (SMAP) and
Supervisor Memory Execution Prevention (SMEP) were introduced in recent systems. The first one prevents
the OS from accessing the memory of an unprivileged process unless a specific code path is followed, and
the second one prevents the OS from executing the memory of an unprivileged process at all times. RISC-V
already includes support for SMAP, through the sstatus.SUM bit, and for SMEP by always denying execution
of virtual memory pages marked with the U bit, with Supervisor mode (OS) privileges, as mandated on the
Privilege Spec.

However, there are no such mechanisms available on Machine mode in the current (v1.11) Privileged Spec.
It is not possible for a PMP rule to be enforced only on non-Machine modes and denied on Machine mode,
to only allow access to a memory region by less-privileged modes. It is only possible to have a locked
rule that will be enforced on all modes, or a rule that will be enforced on non-Machine modes and be
ignored by Machine mode. So for any physical memory region which is not protected with a Locked rule,
Machine mode has unlimited access, including the ability to execute it.

Without being able to protect less-privileged modes from Machine mode, it is not possible to prevent
the mentioned attack vector. This becomes even more important for RISC-V than on other architectures,
since implementations are allowed where a hart only has Machine and User modes available, so the whole
OS will run on Machine mode instead of the non-existent Supervisor mode. In such implementations the
attack surface is greatly increased, and the same kind of attacks performed on Supervisor mode and
mitigated through SMAP/SMEP, can be performed on Machine mode without any available mitigations. Even
on implementations with Supervisor mode present attacks are still possible against the Firmware and/or
the Secure Monitor running on Machine mode.

The proposal is given as:

1. Machine Security Configuration (mseccfg) is a new RW Machine mode CSR, used for
configuring various security mechanisms present on the hart, and only accessible to Machine
mode. It is 64 bits wide, and is at address 0x747 on RV64 and 0x747 (low 32bits), 0x757 (high
32bits) on RV32. All mseccfg fields defined on this proposal are WARL, and the remaining bits are
reserved for future standard use and should always read zero. The reset value of mseccfg is
implementation-specific, otherwise if backwards compatibility is a requirement it should reset to
zero on hard reset.

2. On mseccfg we introduce a field on bit 2 called Rule Locking Bypass (mseccfg.RLB) with the
following functionality:

a. When mseccfg.RLB is 1 locked PMP rules may be removed/modified and locked PMP entries may be edited.

b. When mseccfg.RLB is 0 and pmpcfg.L is 1 in any rule or entry (including disabled entries), then
mseccfg.RLB remains 0 and any further modifications to mseccfg.RLB are ignored until a PMP reset.

3. On mseccfg we introduce a field in bit 1 called Machine-Mode Allowlist Policy (mseccfg.MMWP).
This is a sticky bit, meaning that once set it cannot be unset until a PMP reset. When set it
changes the default PMP policy for M-mode when accessing memory regions that don't have a
matching PMP rule, to denied instead of ignored.

4. On mseccfg we introduce a field in bit 0 called Machine Mode Lockdown (mseccfg.MML). This is
a sticky bit, meaning that once set it cannot be unset until a PMP reset. When mseccfg.MML is set
the system's behavior changes in the following way:

a. The meaning of pmpcfg.L changes: Instead of marking a rule as locked and enforced in all
modes, it now marks a rule as M-mode-only when set and S/U-mode-only when unset. The
formerly reserved encoding of pmpcfg.RW=01 , and the encoding pmpcfg.LRWX=1111 , now encode a
Shared-Region.

An M-mode-only rule is enforced on Machine mode and denied in Supervisor or User mode. It
also remains locked so that any further modifications to its associated configuration or
address registers are ignored until a PMP reset, unless mseccfg.RLB is set.

An S/U-mode-only rule is enforced on Supervisor and User modes and denied on Machine mode.

A Shared-Region rule is enforced on all modes, with restrictions depending on the pmpcfg.L and
pmpcfg.X bits:

- A Shared-Region rule where pmpcfg.L is not set can be used for sharing data between M-
mode and S/U-mode, so is not executable. M-mode has read/write access to that region,
and S/U-mode has read access if pmpcfg.X is not set, or read/write access if pmpcfg.X is set.

- A Shared-Region rule where pmpcfg.L is set can be used for sharing code between M-mode
and S/U-mode, so is not writable. Both M-mode and S/U-mode have execute access on the
region, and M-mode also has read access if pmpcfg.X is set. The rule remains locked so that
any further modifications to its associated configuration or address registers are ignored
until a PMP reset, unless mseccfg.RLB is set.

- The encoding pmpcfg.LRWX=1111 can be used for sharing data between M-mode and S/U
mode, where both modes only have read-only access to the region. The rule remains locked
so that any further modifications to its associated configuration or address registers are
ignored until a PMP reset, unless mseccfg.RLB is set.

b. Adding a rule with executable privileges that either is M-mode-only or a locked Shared-
Region is not possible and such pmpcfg writes are ignored, leaving pmpcfg unchanged. This
restriction can be temporarily lifted by setting mseccfg.RLB e.g. during the boot process.

c. Executing code with Machine mode privileges is only possible from memory regions with a
matching M-mode-only rule or a locked Shared-Region rule with executable privileges.
Executing code from a region without a matching rule or with a matching S/U-mode-only rule is
denied.

d. If mseccfg.MML is not set, the combination of pmpcfg.RW=01 remains reserved for future standard use.

The truth table when the `mseccfg.MML` is set:

[cols="4*^.^1,2*^.^3", separator="!", %autowidth, options="header"]
!====
4+^! Bits on _pmpcfg_ register 2+^! Result
! L ! R ! W ! X ! M Mode ! S/U Mode

! 0 ! 0 ! 0 ! 0 2+^! Inaccessible region (Access Exception)
! 0 ! 0 ! 0 ! 1 ! Access Exception ! Execute-only region
! 0 ! 0 ! 1 ! 0 2+^! Shared data region: Read/write on M mode, Read-only on S/U mode
! 0 ! 0 ! 1 ! 1 2+^! Shared data region: Read/write for both M and S/U mode
! 0 ! 1 ! 0 ! 0 ! Access Exception ! Read-only region
! 0 ! 1 ! 0 ! 1 ! Access Exception ! Read/Execute region
! 0 ! 1 ! 1 ! 0 ! Access Exception ! Read/Write region
! 0 ! 1 ! 1 ! 1 ! Access Exception ! Read/Write/Execute region
! 1 ! 0 ! 0 ! 0 2+^! Locked inaccessible region* (Access Exception)
! 1 ! 0 ! 0 ! 1 ! Locked Execute-only region* ! Access Exception
! 1 ! 0 ! 1 ! 0 2+^! Locked Shared code region: Execute only on both M and S/U mode.*
! 1 ! 0 ! 1 ! 1 2+^! Locked Shared code region: Execute only on S/U mode, read/execute on M mode.*
! 1 ! 1 ! 0 ! 0 ! Locked Read-only region* ! Access Exception
! 1 ! 1 ! 0 ! 1 ! Locked Read/Execute region* ! Access Exception
! 1 ! 1 ! 1 ! 0 ! Locked Read/Write region* ! Access Exception
! 1 ! 1 ! 1 ! 1 2+^! Locked Shared data region: Read only on both M and S/U mode.*
!====

*Locked rules cannot be removed or modified until a PMP reset, unless mseccfg.RLB is set.

Since all fields defined on mseccfg as part of this proposal are locked when set (MMWP/MML) or locked
when cleared (RLB), software can't poll them for determining the presence of Smepmp. It is expected
that BootROM will set mseccfg.MMWP and/or mseccfg.MML during early boot, before jumping to the
firmware, so that the firmware will be able to determine the presence of Smepmp by reading mseccfg
and checking the state of mseccfg.MMWP and mseccfg.MML.

params:
MSECCFG_MML_TYPE:
schema:
type: string
enum: [read-only-0, read-only-1, sticky]
description: |
Determines the behavior of the mseccfg.MML bit:

* "read-only-0": Bit is hardwired to 0
* "read-only-1": Bit is hardwired to 1
* "sticky": Bit resets to 0, can be set to 1 by software, but once set it cannot be cleared until reset.
MSECCFG_MMWP_TYPE:
schema:
type: string
enum: [read-only-0, read-only-1, sticky]
description: |
Determines the behavior of the mseccfg.MMWP bit:

* "read-only-0": Bit is hardwired to 0
* "read-only-1": Bit is hardwired to 1
* "sticky": Bit resets to 0, can be set to 1 by software, but once set it cannot be cleared until reset.
MUTABLE_MSECCFG_RLB:
schema:
type: boolean
description: |
When set, mseccfg.RLB is writable.
When clear, mseccfg.RLB is read-only-0.
Loading