Return-oriented and jump-oriented programming hijack a program’s own code by redirecting indirect control transfers. Zicfilp’s landing pads landing pad Zicfilp forward-edge CFI: the LPAD instruction marks every valid indirect call/jump target. An indirect branch arms ELP=LP_EXPECTED; if the target isn't an LPAD (with a matching 20-bit label in x7, when labeling is used), a software-check exception fires — shrinking the ROP/JOP gadget space to landing-pad-preceded entry points. defined in ch. I·34 — open in glossary close the forward edge (indirect calls and jumps); Zicfiss shadow stacks close the backward edge (returns). The privileged enable/gating machinery is ch. II·16; this is the unprivileged instruction side.
The LPAD instruction
| Mechanism | |
|---|---|
| LPAD placement | The compiler emits an LPAD as the first instruction of every address-taken function and at every indirect jump target. Directly-reached code needs none. |
| ELP tracking | When Zicfilp is active, an indirect call/jump sets ELP = LP_EXPECTED, requiring the target’s first instruction to be an LPAD. If it isn’t → software-check exception (cause 18, xtval = 2). |
| Encoding | LPAD uses the AUIPC major opcode with rd = x0. |
| 20-bit labels (optional) | A call site loads the expected label into x7 before the branch; LPAD faults unless its embedded label matches — constraining each site to a specific target set. |
Labeling: from coarse to fine
| Approach | |
|---|---|
| Single label | One label for the whole program — coarse: any address-taken function is reachable from any indirect site, but gadgets must still start at a landing pad (big gadget-space reduction). |
| Signature / MAC | Label = a hash of the function prototype, so a call site reaches only type-compatible targets. |
| Control-flow-graph | Labels derived from CFG analysis; multi-label functions get per-call-site entry points (each with its own LPAD) so a shared callee is reachable only from its actual callers. |
Hardware Designer Notes
The forward-edge hardware is tiny: one ELP flop, a decode check for the LPAD encoding, and a 20-bit label comparator against x7. The security comes almost free once the toolchain instruments the binaries — which is why RVA23 mandates it. The backward edge (shadow stacks) is the next page.
Minimal Linux-boot hart MUST
- Implement ELP as a one-bit state armed by indirect call/jump and checked at the next instruction (LPAD or fault); preserve it across traps per ch. II·16
- Decode LPAD in the AUIPC-rd=x0 encoding, comparing its 20-bit label against x7 when labeling is enabled
- Raise software-check (cause 18, xtval=2) on a missing or mismatched landing pad
MAY simplify / trap-and-emulate
- Skip Zicfilp on a Linux-boot v1 (binaries degrade to unprotected via the AUIPC-x0 no-op); RVA23 mandates it, so plan the ELP flop
- Implement single-label (coarse) CFI first; labeling is a decode comparison you can add
Check yourself — landing pads
1.An indirect JALR jumps to an address whose first instruction is NOT an LPAD, with Zicfilp active. What happens?
2.What do LPAD's optional 20-bit labels (via x7) achieve over unlabeled landing pads?
3.Why is LPAD encoded in the AUIPC major opcode with rd=x0?