diff options
Diffstat (limited to 'src/priv-cfi.adoc')
-rw-r--r-- | src/priv-cfi.adoc | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/src/priv-cfi.adoc b/src/priv-cfi.adoc new file mode 100644 index 0000000..1b03257 --- /dev/null +++ b/src/priv-cfi.adoc @@ -0,0 +1,374 @@ +[[priv-cfi]] +== Control-flow Integrity (CFI) + +Control-flow Integrity (CFI) capabilities help defend against Return-Oriented +Programming (ROP) and Call/Jump-Oriented Programming (COP/JOP) style +control-flow subversion attacks. The Zicfiss and Zicfilp extensions provide +backward-edge and forward-edge control flow integrity respectively. Please see +the Control-flow Integrity chapter of the Unprivileged ISA specification for further +details on these CFI capabilities and the associated Unprivileged ISA. + +[[priv-forward]] +=== Landing Pad (Zicfilp) + +This section specifies the Privileged ISA for the Zicfilp extension. + +[[FCIFIACT]] +==== Landing-Pad-Enabled (LPE) State + +The term `xLPE` is used to determine if forward-edge CFI using landing pads +provided by the Zicfilp extension is enabled at a privilege mode. + +When S-mode is implemented, it is determined as follows: + +.`xLPE` determination when S-mode is implemented +[width=100%] +[%header, cols="^4,^12"] +|=== +|Privilege Mode| xLPE +| M | `mseccfg.MLPE` +| S or HS | `menvcfg.LPE` +| VS | `henvcfg.LPE` +| U or VU | `senvcfg.LPE` +|=== + +When S-mode is not implemented, it is determined as follows: + +.`xLPE` determination when S-mode is not implemented +[width=100%] +[%header, cols="^4,^12"] +|=== +|Privilege Mode| xLPE +| M | `mseccfg.MLPE` +| U | `menvcfg.LPE` +|=== + +[NOTE] +==== +The Zicfilp must be explicitly enabled for use at each privilege mode. + +Programs compiled with the `LPAD` instruction continue to function correctly, +but without forward-edge CFI protection, when the Zicfilp extension is not +implemented or is not enabled. +==== + +<<< + +[[ZICFILP_FORWARD_TRAPS]] +==== Preserving Expected Landing Pad State on Traps + +A trap may need to be delivered to the same or to a higher privilege mode upon +completion of `JALR`/`C.JALR`/`C.JR`, but before the instruction at the target +of indirect call/jump was decoded, due to: + +* Asynchronous interrupts. +* Synchronous exceptions with priority higher than that of a software-check + exception with `__x__tval` set to "landing pad fault (code=2)" (See + <<exception-priority>> of Privileged Specification). + +The software-check exception caused by Zicfilp has higher priority than an +illegal-instruction exception but lower priority than instruction access-fault. + +The software-check exception due to the instruction not being an `LPAD` +instruction when `ELP` is `LP_EXPECTED` or an software-check exception caused by +the `LPAD` instruction itself (See <<LP_INST>>) leads to a trap being delivered +to the same or to a higher privilege mode. + +In such cases, the `ELP` prior to the trap, the previous `ELP`, must be +preserved by the trap delivery such that it can be restored on a return from the +trap. To store the previous `ELP` state on trap delivery to M-mode, an `MPELP` +bit is provided in the `mstatus` CSR. To store the previous `ELP` state on trap +delivery to S/HS-mode, an `SPELP` bit is provided in the `mstatus` CSR. The +`SPELP` bit in `mstatus` can be accessed through the `sstatus` CSR. To store +the previous `ELP` state on traps to VS-mode, a `SPELP` bit is defined in the +`vsstatus` (VS-modes version of `sstatus`). To store the previous `ELP` state on +transition to Debug Mode, a `pelp` bit is defined in the `dcsr` register. + +When a trap is taken into privilege mode `x`, the `__x__PELP` is set to `ELP` +and `ELP` is set to `NO_LP_EXPECTED`. + +An `MRET` or `SRET` instruction is used to return from a trap in M-mode or +S-mode, respectively. When executing an `__x__RET` instruction, if `__x__PP` +holds the value `y`, then `ELP` is set to the value of `__x__PELP` if `__y__LPE` +is 1; otherwise, it is set to `NO_LP_EXPECTED`; `__x__PELP` is set to +`NO_LP_EXPECTED`. + +Upon entry into Debug Mode, the `pelp` bit in `dcsr` is updated with the `ELP` +at the privilege level the hart was previously in, and the `ELP` is set to +`NO_LP_EXPECTED`. When a hart resumes from Debug Mode, if `dcsr.prv` holds the +value `y`, then `ELP` is set to the value of `pelp` if `__y__LPE` is 1; +otherwise, it is set to `NO_LP_EXPECTED`. + +When the Smrnmi extension is implemented, a `MNPELP` field (bit 9) +is provided in the `mnstatus` CSR to hold the previous `ELP` state on a trap to +the RNMI handler. When a RNMI trap is delivered, the `MNPELP` is set to `ELP` +and `ELP` set to `NO_LP_EXPECTED`. Upon a `MNRET`, if the `mnstatus.MNPP` holds +the value `y`, then `ELP` is set to the value of `MNPELP` if `yLPE` is 1; +otherwise, it is set to `NO_LP_EXPECTED`. + +[NOTE] +==== +The trap handler in privilege mode `x` must save the `__x__PELP` bit and the +`x7` register before performing an indirect call/jump if `xLPE=1`. If the +privilege mode `x` can respond to interrupts and `xLPE=1`, then the trap handler +should also save these values before enabling interrupts. + +The trap handler in privilege mode `x` must restore the saved `__x__PELP` bit +and the `x7` register before executing the `__x__RET` instruction to return from +a trap. +==== + +<<< + +[[priv-backward]] +=== Shadow Stack (Zicfiss) + +This section specifies the Privileged ISA for the Zicfiss extension. + +==== Shadow Stack Pointer (`ssp`) CSR access control + +Attempts to access the `ssp` CSR may result in either an illegal-instruction +exception or a virtual instruction exception, contingent upon the state of the +*__x__*`envcfg.SSE` fields. The conditions are specified as follows: + +* If the privilege mode is less than M and `menvcfg.SSE` is 0, an + illegal-instruction exception is raised. +* Otherwise, if in U-mode and `senvcfg.SSE` is 0, an illegal-instruction + exception is raised. +* Otherwise, if in VS-mode and `henvcfg.SSE` is 0, a virtual instruction + exception is raised. +* Otherwise, if in VU-mode and either `henvcfg.SSE` or `senvcfg.SSE` is 0, + a virtual instruction exception is raised. +* Otherwise, the access is allowed. + +==== Shadow-Stack-Enabled (SSE) State + +The term `xSSE` is used to determine if backward-edge CFI using shadow stacks +provided by the Zicfiss extension is enabled at a privilege mode. + +When S-mode is implemented, it is determined as follows: + +.`xSSE` determination when S-mode is implemented +[width=100%] +[%header, cols="^4,^12"] +|=== +|Privilege Mode| `xSSE` +| M | `0` +| S or HS | `menvcfg.SSE` +| VS | `henvcfg.SSE` +| U or VU | `senvcfg.SSE` +|=== + +When S-mode is not implemented, then `xSSE` is 0 at both M and U privilege modes. + +[NOTE] +==== +Activating Zicfiss in U-mode must be done explicitly per process. Not activating +Zicfiss at U-mode for a process when that application is not compiled with +Zicfiss allows it to invoke shared libraries that may contain Zicfiss +instructions. The Zicfiss instructions in the shared library revert to their +Zimop/Zcmop-defined behavior in this case. + +When Zicfiss is enabled in S-mode it is benign to use an operating system that is +not compiled with Zicfiss instructions. Such an operating system that does +not use backward-edge CFI for S-mode execution may still activate Zicfiss for +U-mode applications. + +When programs that use Zicfiss instructions are installed on a processor that +supports the Zicfiss extension but the extension is not enabled at the privilege +mode where the program executes, the program continues to function correctly but +without backward-edge CFI protection as the Zicfiss instructions will revert to +their Zimop/Zcmop-defined behavior. + +When programs that use Zicfiss instructions are installed on a processor that +does not support the Zicfiss extension but supports the Zimop and Zcmop +extensions, the programs continues to function correctly but without +backward-edge CFI protection as the Zicfiss instructions will revert to their +Zimop/Zcmop-defined behavior. + +On processors that do not support Zimop/Zcmop extensions, all Zimop/Zcmop code +points including those used for Zicfiss instructions may cause an +illegal-instruction exception. Execution of programs that use these instructions +on such machines is not supported. + +Activating Zicfiss in M-mode is currently not supported. Additionally, when +S-mode is not implemented, activation in U-mode is also not supported. These +functionalities may be introduced in a future standard extension. +==== + +[[SSMP]] +==== Shadow Stack Memory Protection + +To protect shadow stack memory, the memory is associated with a new page type – +the Shadow Stack (SS) page – in the single-stage and VS-stage page tables. The +encoding `R=0`, `W=1`, and `X=0`, is defined to represent an SS page. When +`menvcfg.SSE=0`, this encoding remains reserved. Similarly, when `V=1` and +`henvcfg.SSE=0`, this encoding remains reserved at `VS` and `VU` levels. + +If `satp.MODE` (or `vsatp.MODE` when `V=1`) is set to `Bare` and the effective +privilege mode is below M, shadow stack memory accesses are prohibited, and +shadow stack instructions will raise a store/AMO access-fault exception. When +the effective privilege mode is M, any memory access by an `SSAMOSWAP.W/D` +instruction will result in a store/AMO access-fault exception. + +Memory mapped as an SS page cannot be written to by instructions other than +`SSAMOSWAP.W/D`, `SSPUSH`, and `C.SSPUSH`. Attempts will raise a store/AMO +access-fault exception. Implicit accesses, including instruction fetches to an SS +page, are not permitted. Such accesses will raise an access-fault exception +appropriate to the access type. However, the shadow stack is readable by all +instructions that only load from memory. + +[NOTE] +==== +Stores to shadow stack pages by instructions other than `SSAMOSWAP`, `SSPUSH`, +and `C.SSPUSH` will trigger a store/AMO access-fault exception, not a store/AMO +page-fault exception, signaling a fatal error. A store/AMO page-fault suggests +that the operating system could address and rectify the fault, which is not +feasible in this scenario. Hence, the page fault handler must decode the opcode +of the faulting instruction to discern whether the fault was caused by a +non-shadow-stack instruction writing to an SS page (a fatal condition) or by a +shadow stack instruction to a non-resident page (a recoverable condition). The +performance-critical nature of operating system page fault handlers necessitates +triggering an access-fault instead of a page fault, allowing for a +straightforward distinction between fatal conditions and recoverable faults. + +Operating systems must ensure that no writable, non-shadow-stack alias virtual +address mappings exist for the physical memory backing the shadow stack. +Furthermore, in systems where an address-misaligned exception supersedes the +access-fault exception, handlers emulating misaligned stores must be designed to +cause an access-fault exception when the store is directed to a shadow stack +page. + +All instructions that perform load operations are allowed to read from the +shadow stack. This feature facilitates debugging and performance profiling by +allowing examination of the link register values backed up in the shadow stack. +==== + +[NOTE] +==== +As of the drafting of this specification, instruction fetches are the sole type +of implicit access subjected to single- or VS-stage address translation. +==== + +If a shadow stack (SS) instruction raises an access-fault, page-fault, or +guest-page-fault exception that is supposed to indicate the original instruction +type (load or store/AMO), then the reported exception cause is respectively a +store/AMO access fault (code 7), a store/AMO page fault (code 15), or a +store/AMO guest-page fault (code 23). For shadow stack instructions, the +reported instruction type is always as though it were a store or AMO, even for +instructions `SSPOPCHK` and `C.SSPOPCHK` that only read from memory and do not +write to it. + +[NOTE] +==== +When Zicfiss is implemented, the existing "store/AMO" exceptions can be thought +of as "store/AMO/SS" exceptions, indicating that the trapping instruction is +either a store, an AMO, or a shadow stack instruction. +==== + +[NOTE] +==== +The H (hypervisor) extension specifies that when a guest-page fault is caused by +an implicit memory access of VS-stage address translation, the reported +exception is either a load or store/AMO guest-page fault based not on the +original instruction type but rather on whether the memory access attempted for +VS-stage translation was a read or a write of memory. VS-stage address +translation can thus cause a shadow stack instruction to raise a load +guest-page-fault exception. +==== + +Shadow stack instructions are restricted to accessing shadow stack +(`pte.xwr=010b`) pages. Should a shadow stack instruction access a page that is +not designated as a shadow stack page and is not marked as read-only +(`pte.xwr=001`), a store/AMO access-fault exception will be invoked. Conversely, +if the page being accessed by a shadow stack instruction is a read-only page, a +store/AMO page-fault exception will be triggered. + + +[NOTE] +==== +Shadow stack loads and stores will trigger a store/AMO page-fault if the +accessed page is read-only, to support copy-on-write (COW) of a shadow stack +page. If the page has been marked read-only for COW tracking, the page fault +handler responds by creating a copy of the page and updates the `pte.xwr` to +`010b`, thereby designating each copy as a shadow stack page. Conversely, if +the access targets a genuinely read-only page, the fault being reported as a +store/AMO page-fault signals to the operating system that the fault is fatal +and non-recoverable. Reporting the fault as a store/AMO page-fault, even for +`SSPOPCHK` initiated memory access, aids in the determination of fatality; if +these were reported as load page-faults, access to a truly read-only page +might be mistakenly treated as a recoverable fault, leading to the faulting +instruction being retried indefinitely. The PTE does not provide a read-only +shadow stack encoding. + +Attempts by shadow stack instructions to access pages marked as read-write, +read-write-execute, read-execute, or execute-only result in a store/AMO +access-fault exception, similarly indicating a fatal condition. + +Shadow stacks should be bounded at each end by guard pages to prevent accidental +underflows or overflows from one shadow stack into another. Conventionally, a +guard page for a stack is a page that is not accessible by the process that owns +the stack. +==== + +<<< + +If the virtual address in `ssp` is not `XLEN` aligned, then the `SSPUSH`/ +`C.SSPUSH`/`SSPOPCHK`/`C.SSPOPCHK` instructions cause a store/AMO access-fault +exception. + +[NOTE] +==== +Misaligned accesses to shadow stack are not required and enforcing alignment is +more secure to detect errors in the program. An access-fault exception is raised +instead of address-misaligned exception in such cases to indicate fatality and +that the instruction must not be emulated by a trap handler. +==== + +Correct execution of shadow stack instructions that access memory requires the +the accessed memory to be idempotent. If the memory referenced by +`SSPUSH`/`C.SSPUSH`/`SSPOPCHK`/`C.SSPOPCHK`/`SSAMOSWAP.W/D` instructions is not +idempotent, then the instructions cause a store/AMO access-fault exception. + +[NOTE] +==== +The `SSPOPCHK` instruction performs a load followed by a check of the loaded +data value with the link register as source. If the check against the link +register faults, and the instruction is restarted by the trap handler, then the +instruction will perform a load again. If the memory from which the load is +performed is non-idempotent, then the second load may cause unexpected side +effects. Shadow stack instructions that access the shadow stack require the +memory referenced by `ssp` to be idempotent to avoid such concerns. Locating +shadow stacks in non-idempotent memory, such as non-idempotent device memory, +is not an expected usage, and requiring memory referenced to be idempotent +does not pose a significant restriction. +==== + +The `U` and `SUM` bit enforcement is performed normally for shadow stack +instruction initiated memory accesses. The state of the `MXR` bit does not +affect read access to a shadow stack page as the shadow stack page is always +readable by all instructions that load from memory. + +The G-stage address translation and protections remain unaffected by the Zicfiss +extension. The `xwr == 010b` encoding in the G-stage PTE remains reserved. When +G-stage page tables are active, the shadow stack instructions that access memory +require the G-stage page table to have read-write permission for the accessed +memory; else a store/AMO guest-page fault exception is raised. + +[NOTE] +==== +A future extension may define a shadow stack encoding in the G-stage page table +to support use cases such as a hypervisor enforcing shadow stack protections for +its guests. +==== + +Svpbmt and Svnapot extensions are supported for shadow stack pages. + +The PMA checks are extended to require memory referenced by shadow stack +instructions to be idempotent. The PMP checks are extended to require read-write +permission for memory accessed by shadow stack instructions. If the PMP does not +provide read-write permissions or if the accessed memory is not idempotent then +a store/AMO access-fault exception is raised. + +The `SSAMOSWAP.W/D` instructions require the PMA of the accessed memory range to +provide AMOSwap level support. |