diff --git a/spec/std/isa/csr/mseccfg.yaml b/spec/std/isa/csr/mseccfg.yaml index 0329d08a1..fca2dd729 100644 --- a/spec/std/isa/csr/mseccfg.yaml +++ b/spec/std/isa/csr/mseccfg.yaml @@ -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; diff --git a/spec/std/isa/csr/mseccfgh.yaml b/spec/std/isa/csr/mseccfgh.yaml index 63daf6f40..b60a3a628 100644 --- a/spec/std/isa/csr/mseccfgh.yaml +++ b/spec/std/isa/csr/mseccfgh.yaml @@ -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: {} diff --git a/spec/std/isa/ext/Smepmp.yaml b/spec/std/isa/ext/Smepmp.yaml new file mode 100644 index 000000000..ec1280cf8 --- /dev/null +++ b/spec/std/isa/ext/Smepmp.yaml @@ -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.