Skip to content

Latest commit

 

History

History
346 lines (281 loc) · 12.7 KB

cfi_forward.adoc

File metadata and controls

346 lines (281 loc) · 12.7 KB

Forward-edge control-flow integrity

The forward-edge CFI introduces landing pad instructions that enable software to indicate valid targets for indirect calls and indirect jumps in a program.

A landing pad (lpcul) instruction is defined as the instruction that must be placed at the program locations that can be valid targets of indirect jumps or calls.

To enforce that the target of an indirect call or indirect jump must be a valid landing pad instruction, the hart maintains an expected landing pad (ELP) state to determine if a landing pad instruction is required at the target of a JALR instruction. The ELP state can be one of:

  • 0 - NO_LP_EXPECTED

  • 1 - LP_EXPECTED

A JALR with rd = x1 or rd = x5 is an indirect call; it updates ELP to LP_EXPECTED. A JALR with rd != x1 and rd != x5 and where rs1 != x1 and rs1 != x5 is an indirect jump; it updates the ELP to LP_EXPECTED.

When ELP is set to LP_EXPECTED and the next instruction in the instruction stream is not lpcll, then an illegal instruction exception is raised. If the next instruction in the instruction stream is lpcll then the ELP updates to NO_LP_EXPECTED.

Note

Tracking of ELP and requiring valid landing pad instructions at the target of indirect call and jump enables a processor implementation to significantly reduce or to prevent speculation to non-landing-pad instructions. Constraining speculation using this technique greatly reduces the gadget space and increases the difficulty of using techniques such as branch-target-injection, also known as Spectre variant 2, that use speculative execution to leak data through side channels.

The forward-edge CFI also supports labeling of landing pads. By itself a landing pad allows, for example, an indirect call to land on any lpcll in the program. This significantly reduces the number of valid targets for an indirect call. Labeling of the landing pads enables software to achieve greater precision in pairing up indirect call sites or indirect jump sites with valid targets. To support labeled landing pads, the indirect call/jump sites establish an expected landing pad label in the landing pad label register (lplr). If the target of the indirect call/jump is a valid landing pad instruction, the expected label established in the lplr is matched with the target’s label. If a mismatch is detected then the label check instruction causes an illegal instruction exception.

Each landing pad may be labeled with a label that may be upto 25-bits wide. The lplr has three subfields - a 9-bit lower label (LL), a 8-bit middle label (ML), and an 8-bit upper label (UL).

The forward-edge CFI provides a lpsll instruction to establish the expected LL in the lplr, a lpsml instruction to establish the ML, and a lpsul instruction to establish the UL in the lplr.

The lpcll instructions embed a 9-bit immediate field. The instruction compares this value to the LL and on a mismatch causes an illegal-instruction exception.

For label widths up to 17-bit a companion instruction lpcml is provided. The lpcml embeds a 8-bit immediate value that is compared to the ML and on a mismatch causes an illegal-instruction exception.

For label widths greater than 17-bit a second companion instruction lpcul is provided. The lpcul embeds a 8-bit immediate value that is compared to the UL and on a mismatch causes an illegal-instruction exception.

Forward-edge CFI Instruction encoding

The forward-edge CFI introduces the following instructions for landing pad operations. All instructions are encoded using the SYSTEM major opcode and using the mop.rr instructions defined by the Zimops extension.

(mop.rr) 31 25 24 23 22 15 14 12 11 7 6 0

mnemonic

1.00..1

t

t

tttsssss

func3

rd

opcode

lpsll

1000001

0

LLPL

100

0

1110011

lpcll

1000001

1

LLPL

100

0

1110011

lpsml

1000011

0

0

MLPL

100

0

1110011

lpcml

1000011

0

1

MLPL

100

0

1110011

lpsul

1000101

1

0

ULPL

100

0

1110011

lpcul

1000101

1

1

ULPL

100

0

1110011

7

1

1

8

3

5

7

When privilege level is M, the forward-edge CFI is active when MFCFIEN is 1 in mstatus register.

When menvcfg.CFI is 0, then Zisslpcfi is not enabled for privilege modes less than M and forward-edge CFI is not active at privilege levels less than M.

When V=0 and menvcfg.CFI is 1, then forward-edge CFI is active at S-mode if mstatus.SFCFIEN is 1 and is active at U-mode if mstatus.UFCFIEN is 1.

When henvcfg.CFI is 0, then Zisslpcfi is not enabled for use when V=1.

When V=1 and menvcfg.CFI and henvcfg.CFI are both 1, then forward-edge CFI is active at S-mode if vsstatus.SFCFIEN is 1 and is active at U-mode if vsstatus.UFCFIEN is 1.

The term xFCFIACT is used to determine if forward-edge CFI is active at privilege level x and is defined as follows:

xFCFIACT determination
if ( privilege == M-mode )
    xFCFIACT = mstatus.MFCFIEN
else if ( menvcfg.CFI == 1 && V == 0 && privilege == S-mode )
    xFCFIACT = mstatus.SFCFIEN
else if ( menvcfg.CFI == 1 && V == 0 && privilege == U-mode )
    xFCFIACT = mstatus.UFCFIEN
else if ( menvcfg.CFI == 1 && henvcfg.CFI == 1 & V == 1 && privilege == S-mode )
    xFCFIACT = vsstatus.SFCFIEN
else if ( menvcfg.CFI == 1 && henvcfg.CFI == 1 & V == 1 && privilege == U-mode )
    xFCFIACT = vsstatus.UFCFIEN
else
    xFCFIACT = 0

When forward-edge CFI is not active(xFCFIACT = 0):

  • The implementation does not update expected landing pad (ELP) state on indirect call or jump and does not require the instruction at the target of a indirect call or jump to be a landing pad instruction.

  • The implementation does not update expected landing pad (ELP) when lpcll is executed.

  • The instructions defined for forward-edge CFI revert to their Zimops defined behavior and write 0 to [rd].

Landing pad instruction

lpcll is the valid landing pad instructions at target of indirect jumps and indirect calls. When a forward-edge CFI is active, the instructions cause an illegal instruction exception if they are not placed at a 4-byte aligned pc. The lpcll has the lower landing pad label embedded in the LLPL field. lpcll causes an illegal instruction exception if the LLPL field in the instruction does not match the lplr.LL field.

When the instructions cause an illegal-instruction exception, the ELP does not change.

The operation of the lpcll instruction is as follows:

lpcll operation
If xFCFIACT != 0
    // If PC not 4-byte aligned then illegal-instruction
    if pc[1:0] != 0
        Cause illegal-instruction exception
    // If lower landing pad label not matched -> illegal-instruction
    else if (inst.LLPL != lplr.LL)
        Cause illegal-instruction exception
    else
        ELP = NO_LP_EXPECTED
else
    [rd] = 0;
endif

Label matching instructions

The lpcml instruction matches the 8-bit wide middle label in its MLPL field with the lplr.ML field and causes an illegal instruction exception on a mismatch. The lpcml is not a valid target for an indirect call or jump.

The lpcul instruction matches the 8-bit wide upper label in its ULPL field with the lplr.UL field and causes an illegal instruction exception on a mismatch. The lpcul is not a valid target for an indirect call or jump.

The operation of the lpcml instruction is as follows:

lpcml operation
If xFCFIACT != 0
    if (lplr.ML != inst.MLPL)
        cause illegal-instruction exception
else
    [dst] = 0;
endif

The operation of the lpcul instruction is as follows:

lpcul operation
If xFCFIACT != 0
    if (lplr.UL != inst.ULPL)
        cause illegal-instruction exception
else
    [dst] = 0;
endif

Setting up landing pad label register

Before performing an indirect call or indirect jump to a labeled landing pad, the lplr is loaded with the expected landing pad label - a constant determined at compilation time.

A lpsll instruction is provided to set the value of the lower label (LL) field of the lplr.

The operation of this instruction is as follows:

lpsll operation
If xFCFIACT == 1
   lplr.LL = inst.LLPL
   lplr.ML = lplr.UL = 0
else
   [rd] = 0;
endif
Note

The following instruction sequence may be emitted at indirect call sites by the compiler to set up the landing pad label register when labels that are upto 9-bit wide are used:

  :
  # x10 is expected to have address of function bar()
  lpsll $0x1de   # setup lplr.LL with value 0x1de
  jalr %ra, %x10
  :

The following instruction sequence may be emitted at indirect call sites by the compiler to set up the landing pads at entrypoint of function bar():

bar:
    lpcll $0x1de    # Verifies that LPLR.LL matches 0x1de

A lpsml instruction is provided to set the value of the middle label (ML) field of the lplr. This instruction is used when labels wider than 9-bit are used.

The operation of this instruction is as follows:

lpsml operation
If xFCFIACT == 1
   lplr.ML = inst.MLPL
else
   [rd] = 0;
endif
Note

The following instruction sequence may be emitted at indirect call sites by the compiler to set up the landing pad label register when labels that are upto 17-bit wide are used:

  :
  # x10 is expected to have address of function bar()
  lpsll $0x1de   # setup lplr.LL with value 0x1de
  lpsml $0x17   # setup lplr.ML with value 0x17
  jalr %ra, %x10
  :

The following instruction sequence may be emitted at indirect call sites by the compiler to set up the landing pads at entrypoint of function bar():

bar:
    lpcll $0x1de    # Verifies that LPLR.LL matches 0x1de
    lpcml $0x17     # Verifies that LPLR.ML matches 0x17
     :              # continue if landing pad checks succeed

A lpsul instruction is provided to set the value of upper label (UL) field lplr. This instruction is used when labels wider than 17-bit are used.

The operation of this instruction is as follows:

lpsul operation
If xFCFIACT == 1
   lplr.ML = inst.MLPL
else
   [rd] = 0;
endif
Note

The following instruction sequence may be emitted at indirect call sites by the compiler to set up the landing pad label register when labels that are upto 25-bit wide are used:

  :
  # x10 is expected to have address of function bar()
  lpsll $0x1de   # setup lplr.LL with value 0x1de
  lpsml $0x17    # setup lplr.ML with value 0x17
  lpsul $0x13    # setup lplr.UL with value 0x13
  jalr %ra, %x10
  :

The following instruction sequence may be emitted at indirect call sites by the compiler to set up the landing pads at entrypoint of function bar():

bar:
    lpcll $0x1de    # Verifies that LPLR.LL matches 0x1de
    lpcml  $0x17    # Verifies that LPLR.ML matches 0x17
    lpcul  $0x13    # Verifies that LPLR.ML matches 0x13
     :              # continue if landing pad checks succeed
     :

Preserving expected landing pad state on traps

A trap may need to be delivered to the same or higher privilege level on completion of JALR but before the instruction at the target of JALR was decoded. To avoid losing previous ELP state, MPELP and SPELP bits are provided in the mcfistatus CSR for M-mode and HS/S-mode respectively. The SPELP bits can be accessed through the scfistatus CSR. To avoid losing ELP state on traps to VS-mode, SPELP bits are provided in vcfistatus (VS-modes version of scfistatus) to hold the ELP. When a trap is taken into VS-mode, the SPELP bits of vcfistatus CSR are updated with ELP. When V=1, scfistatus aliases to vcfistatus CSR. The xPELP fields in mcfistatus and vcfistatus are WARL fields. The trap handler should preserve the lplr CSR.

When a trap is taken into privilege mode x, the xELP bits are updated with current ELP and ELP is set to NO_LP_EXPECTED.

MRET or SRET instruction is used to return from a trap in M-mode or S-mode respectively. When executing an xRET instruction, the ELP is set to xPELP and xPELP is set to NO_LP_EXPECTED. The trap handler should put back the preserved lplr value before invoking SRET or MRET.