Zicfiss: RISC-V Backward-Edge CFI Extension
- Zicfiss is the RISC-V backward-edge control-flow integrity extension that uses an explicit shadow-stack mechanism to protect function returns.
- It employs dedicated instructions such as sspush and sspopchk along with MMU-enforced shadow-stack page isolation to verify and enforce return address integrity.
- The CVA6-CFI integration shows strong security enhancements with just 1% area overhead and up to 15.6% runtime slowdown, underscoring a trade-off between protection and performance.
Zicfiss is the RISC-V standard Control-Flow Integrity (CFI) extension for backward-edge protection, that is, protection of function returns against tampering. In the RISC-V CFI family, it is paired with Zicfilp, which provides forward-edge protection via landing pads; together they form a standardized ISA-level CFI mechanism for RISC-V based on shadow stack and landing pad primitives. In the CVA6-CFI implementation, Zicfiss is realized through explicit shadow-stack instructions, CSR and privilege-state extensions, MMU-enforced shadow-stack page isolation, and runtime verification of return addresses against protected shadow-stack state (Manoni et al., 4 Feb 2026).
1. Architectural scope and standardization
Zicfiss is defined as the backward-edge half of the newly ratified RISC-V CFI family. Its function is narrowly specified: it protects returns, rather than control-flow edges in general. Zicfilp covers the complementary forward-edge domain through landing pads, while Zicfiss covers return integrity through a shadow stack. The two mechanisms are independent and configurable hardware units in the CVA6 integration, so backward-edge protection can be deployed alone or together with forward-edge protection.
The extension is analogous in spirit to Intel CET and ARM’s BTI/Pointer Authentication, but it is expressed through RISC-V instructions and privilege/state machinery rather than through fully implicit return protection. This distinction is central to the architecture. Zicfiss does not automatically protect every call and return; the mechanism is exposed at the ISA level and must be exercised explicitly by software. A plausible implication is that Zicfiss is designed as a standardized architectural substrate for CFI rather than as a completely transparent hardware retrofit.
2. Security objective and threat model
The security problem addressed by Zicfiss is classic control-flow hijacking in memory-unsafe code. The targeted attack pattern is memory corruption that overwrites control data, especially return addresses, followed by code-reuse exploitation such as return-oriented programming (ROP). The paper’s framing emphasizes why the backward edge is especially exposed: the architectural return target resides in writable stack memory, so a successful overwrite can redirect execution (Manoni et al., 4 Feb 2026).
Zicfiss mitigates this class of attack by maintaining a shadow stack that records return addresses separately from the normal program stack. On return, the expected address recovered from the shadow stack must match the architectural return value. If the values differ, the implementation raises a software check exception. The security property is therefore detection of return-address tampering at runtime, with execution aborted when the architectural and shadow-stack views diverge.
This protection is strong against return-address tampering and ROP-style attacks, but it is not presented as a complete security proof. The design depends on the integrity and isolation of shadow-stack memory and on correct instrumentation of protected code paths. It is therefore more precise to view Zicfiss as a standardized backward-edge integrity mechanism than as a self-sufficient guarantee against all control-flow attacks.
3. Instruction set semantics and software contract
Zicfiss is implemented through a dedicated instruction set rather than implicit push/pop semantics. The instruction set described in the CVA6-CFI work consists of sspush, sspopchk, ssrdp, and ssamoswap. Non-leaf functions save the link register into the shadow stack entry tracked by a dedicated shadow-stack pointer. This yields an explicit software contract: compiler or software instrumentation must emit the shadow-stack operations where needed (Manoni et al., 4 Feb 2026).
The architectural distinction from Intel CET is consequential. Because return-address protection is not automatically performed on every call and return, calling convention and toolchain cooperation become part of the trusted deployment path. This makes the mechanism more explicit and flexible, but also introduces a dependency on compiler instrumentation quality and ABI integration.
The instructions have the following roles:
sspush: shadow stack push.sspopchk: shadow stack pop and check.ssrdp: shadow stack pointer read.ssamoswap: atomic swap on the shadow stack.
The paper also notes compressed forms. In the evaluated user-space benchmarks, ssamoswap did not appear, and ssrdp appeared only once during initial setup. This suggests that the common execution-time cost is dominated by sspush and sspopchk, which align directly with ordinary call/return structure.
4. CVA6 microarchitectural integration
The CVA6 implementation extends the core with a dedicated Shadow Stack Unit (SSU). The SSU sits in the execute path and is responsible both for shadow-stack-specific checks and for filtering instructions before they reach the LSU. The design also extends the CSR file with a Shadow Stack pointer and augments the environment configuration registers for machine, supervisor, and hypervisor modes with a Shadow Stack enable field. That enable field is propagated through the frontend, decode, and execute stages to determine whether Zicfiss is active at a given privilege level (Manoni et al., 4 Feb 2026).
Decode support is explicit. The core recognizes sspush, sspopchk, ssrdp, ssamoswap, and compressed forms. sspush and sspopchk are mapped to store and load instructions, respectively, with special operation tags so that they remain distinguishable from ordinary memory operations deeper in the pipeline. ssamoswap likewise receives dedicated shadow-stack swap W/D identifiers. This organization keeps Zicfiss compatible with the existing load/store machinery while preserving architectural distinction for policy enforcement and exception generation.
Configurability is a notable aspect of the integration. Zicfiss and Zicfilp are separate hardware units, and activation is privilege-sensitive. This supports selective deployment, but it also introduces policy complexity because enablement depends on privilege mode and address-translation state rather than on a single global switch.
5. Enforcement logic, isolation, and exception behavior
The SSU performs two core functions. First, it applies privilege and access-policy filtering. If it detects an ssamoswap executing in machine mode, or detects any Zicfiss instruction running with supervisor/virtual address translation and protection disabled at a privilege level below machine mode, it raises a store access fault and forwards it directly to the scoreboard. Otherwise, the instruction is allowed to access the LSU.
Second, it implements return-address verification for sspopchk. When sspopchk is decoded, the SSU buffers the link register content and the load transaction ID in dedicated registers and marks that an sspopchk is in progress. As load results return from the LSU, the SSU compares each result’s transaction ID with the buffered ID. On a match, it compares the buffered link register value against the loaded shadow-stack value. A mismatch raises a software check exception (Manoni et al., 4 Feb 2026).
The resulting behavior can be summarized operationally as follows: the machine records (link_register_value, load_id) on sspopchk, waits for the LSU response with the matching load_id, and raises an exception if the loaded value does not equal the link register value. This is the architectural essence of the backward-edge CFI mechanism: the return target presented architecturally must equal the protected return target stored on the shadow stack.
The MMU adds a further rule: Zicfiss instructions may access only shadow-stack pages, and non-Zicfiss instructions may access only non-shadow-stack pages. Any violation results in a store access fault. This page-granular isolation is a major security property. It prevents ordinary code from reading or writing the shadow stack and prevents shadow-stack operations from touching unrelated memory. A plausible implication is that Zicfiss relies on a joint ISA-and-MMU enforcement model rather than on shadow-stack convention alone.
6. Quantitative evaluation, overheads, and limitations
In 22 nm GF22FDX synthesis at 800 MHz worst-case conditions, the overall CVA6-CFI area overhead is 1.0%. The paper reports the following block-level changes for the combined CFI design:
| Block | Baseline → CVA6-CFI | Overhead |
|---|---|---|
| CSR Register File | 7831 → 8220 | 5.0% |
| Fetch/Decode | 1101 → 1124 | 2.1% |
| Issue | 25637 → 25788 | 0.6% |
| Execute | 61631 → 61854 | 0.4% |
| Commit | 182 → 372 | 103.6% |
| Total | 96382 → 97358 | 1.0% |
The commit stage more than doubles because of the two landing-pad units, but its contribution to total area remains small. From the standpoint of silicon cost, the combined design is therefore lightweight.
The software overheads are more visible. On the MiBench automotive benchmark subset, CFI instrumentation adds a fairly constant code-size overhead of about 22–23 kB, corresponding to a 7.6–9.2% relative increase. Across benchmarks, CFI instructions account for less than 0.5% of total executed instructions. In performance terms, the combined CFI design introduces up to 15.6% slowdown. The paper attributes most of that runtime cost to shadow stack operations, specifically sspush and sspopchk, because they require memory accesses; by contrast, lpad is resolved in one cycle without execute-stage memory access, so its cost is lower (Manoni et al., 4 Feb 2026).
These measurements identify a clear trade-off. Zicfiss provides strong backward-edge protection with low area cost, but its dominant runtime expense arises from shadow-stack memory traffic. The deployment requirements are equally explicit: compiler or toolchain instrumentation, explicit shadow-stack management, dedicated page isolation for shadow-stack memory, and microarchitectural support in the pipeline. The implementation is presented as a first microarchitectural evaluation rather than an exhaustive security treatment, and it does not evaluate advanced out-of-order or multicore variants. Accordingly, the most precise characterization is that Zicfiss is a standardized, hardware-assisted shadow-stack CFI extension whose principal contribution is robust backward-edge protection with modest but measurable performance cost.