34.1-4CFI I: Landing Pads (Zicfilp)

Part III Linux boot: optional Vol. I (Unprivileged) pp. 561–568 · ~3 min read

  • landing pad

Return-oriented and jump-oriented programming hijack a program’s own code by redirecting indirect control transfers. Zicfilp’s landing pads 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

How forward-edge CFI works
Mechanism
LPAD placementThe 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 trackingWhen 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).
EncodingLPAD 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.
Dotted-underlined cells have explanations — click one.

Labeling: from coarse to fine

Labeling schemes (increasing precision)
Approach
Single labelOne 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 / MACLabel = a hash of the function prototype, so a call site reaches only type-compatible targets.
Control-flow-graphLabels 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.
Dotted-underlined cells have explanations — click one.

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?

3 questions