[[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 <> 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 <>) 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.