16.1-2Control-flow Integrity: Privileged Zicfilp & Zicfiss

Part II Linux boot: optional Vol. II (Privileged) pp. 187–192 · ~4 min read

The CFI instructions — LPAD landing pads (forward-edge, anti-JOP) and the shadow-stack ops (backward-edge, anti-ROP) — live in Volume I. This chapter is their privileged plumbing: who may enable them, and how the MMU protects shadow-stack memory.

Enabling, mode by mode

xLPE / xSSE — which envcfg bit governs each mode (S-mode implemented)
Landing pads (xLPE)Shadow stacks (xSSE)
M-modemseccfg.MLPEHardwired 0
S / HSmenvcfg.LPEmenvcfg.SSE
VShenvcfg.LPEhenvcfg.SSE
U / VUsenvcfg.LPEsenvcfg.SSE
Dotted-underlined cells have explanations — click one.

Disabled modes degrade gracefully: LPAD becomes a no-op and the shadow-stack ops fall back to their Zimop/Zcmop write-zero behavior — so one binary (or shared library) runs on any combination of support and policy. ssp CSR access follows the cascade with the usual trap taxonomy: menvcfg.SSE=0 → illegal-instruction below M; senvcfg.SSE=0 → illegal in U; henvcfg.SSE=0 → virtual-instruction in VS/VU. xSSE changes take effect immediately — no fence required.

Preserving ELP across traps

A trap can strike after JALR retires but before its target decodes — exactly when ELP=LP_EXPECTED is armed. Trap entry to mode x saves ELP into xPELP (mstatus.MPELP, mstatus.SPELP via sstatus, vsstatus.SPELP, dcsr.pelp for Debug Mode) and clears ELP so the handler runs unarmed. On xRET to mode y: ELP ← xPELP if yLPE, else NO_LP_EXPECTED; xPELP clears. The landing-pad software-check (cause 18, stval=2) sits above illegal-instruction but below instruction-access-fault in priority. Handlers making their own indirect calls (or enabling interrupts) must first save xPELP and x7 — the label register is state too.

Shadow-stack memory protection

The PTE encoding xwr = 010 — reserved since Sv32 — becomes the Shadow Stack page when the governing SSE bit is on. The fault matrix is the heart of the design — access-fault means fatal, page-fault means the OS can fix this:

Who may touch an SS page, and what faults say (all SS-instruction faults report STORE/AMO type — codes 7/15/23 — even for the read-only SSPOPCHK)
Result
SSPUSH / C.SSPUSH / SSAMOSWAP → SS pageAllowed — the only writers.
Any load → SS pageAllowed — debuggers and profilers may read saved return addresses. MXR is irrelevant.
Ordinary store / CBO.* / instruction fetch → SS pageStore/AMO ACCESS-fault (fetch: fetch access-fault) — fatal by construction; the page-fault handler never needs to decode opcodes for this.
SS instruction → read-only page (xwr=001)Store/AMO PAGE-fault — the recoverable case.
SS instruction → RW / RX / RWX / X pageStore/AMO ACCESS-fault — fatal; SS instructions may only touch SS or RO pages.
SS instruction with satp/vsatp = Bare (below M), misaligned ssp, or non-idempotent memoryStore/AMO ACCESS-fault — no Bare-mode shadow stacks, no misaligned emulation (deliberately non-emulable), no device-memory stacks (SSPOPCHK restart would double-load).
Dotted-underlined cells have explanations — click one.

U and SUM apply normally. Under H, the G-stage keeps xwr=010 reserved: a guest’s shadow-stack access needs plain read-write G-stage permission or it raises a store/AMO guest-page fault — shadow-stack-ness is purely a VS-stage property (for now). PMA checks extend to require idempotency, PMP to require read-write, and SSAMOSWAP needs AMOSwap-capable memory. Svpbmt and Svnapot compose fine with SS pages.

Hardware Designer Notes

Cost check: ELP machinery is ~5 flops and trap-path muxing; the SS page type is a handful of terms in the already-existing permission PLA plus a new op attribute. The verification burden is the fault matrix — six cases × (single-stage, two-stage, PMP, PMA) — not the datapath.

Minimal Linux-boot hart MUST

  • Add the ELP/xPELP preservation flops to every trap-entry and xRET path (including MNRET and Debug entry/resume), with the yLPE-gated restore
  • Extend the permission checker: xwr=010 ∧ SSE → SS page with the exact fault-type matrix (access = fatal, page = recoverable), keyed by an is-SS-instruction attribute on the memory op
  • Report store/AMO fault types for ALL SS-instruction faults, SSPOPCHK included

MAY simplify / trap-and-emulate

  • Omit both extensions for a Linux-boot v1 (senvcfg/menvcfg bits read zero, xwr=010 stays reserved) — RVA23 mandates them, so plan the PTE-decoder hook
  • Reuse the AMO datapath for SSAMOSWAP; the SS-page qualifier is one extra permission input

Check yourself — privileged CFI

1.A timer interrupt fires between a JALR and the decode of its target. Why must trap entry save ELP, and where?

2.A normal SD instruction targets a shadow-stack page. Which exception, and why NOT a page fault?

3.Why does an SS instruction hitting a READ-ONLY page raise a store/AMO PAGE fault rather than an access fault?

4.Under the H extension, what must the G-stage grant for a guest's shadow-stack access?

4 questions