Control flow integrity extensions (`zicfilp` and `zicfiss`) [1] for risc-v are ratified. `zicfilp` protects forward control flow i.e. indirect function call sites while `zicfiss` protects return control flow i.e. return from functions which have spilled return addresses on stack.
This patchset is based on recent master with patch series from LIU (alibaba) [4] which enables `zimop` and `zcmop` support in qemu. `zicfiss` has a dependency on `zimop` and `zcmop`. zicfilp ------- On a very high level `zicfilp` extends risc-v architecture by introducing a landing pad instruction `lpad` which must be target for every indirect branch except when - rs1 == x1 || x5 (a return from a function) - rs1 == x7 (sw guarded branch) If `lpad` is not present, cpu will raise software check exception (cause=18) , introduced in privileged spec version 1.13. To track `expected landing pad` state on every indirect branch, a new state is introduced in cpu `elp` short for expected landing pad status and can be spilled into *status register if a trap occurs between indirect branch and target instruction. `lpad` instr is carved out of HINT space `auipc rd` with `rd==x0` and can have 20 bit immediate (label_20bit) encoded in it. After an indirect branch lands on `lpad` instruction, cpu performs following checks: -- If label_20bit == 0, no further check are performed. -- If label_20bit != 0, cpu evaluates (label_20bit == x7_upper_20bit) If above expression is evaluated to be false, cpu raises sw check exception. Software can implement more finer-grained control flow using label mechanism defined in `zicfilp` by ensuring x7 has appropriate label setup prior to indirect call and thus further restraining call sites target locations. zicfiss ------- On a very high level `zicfiss` extends risc-v architecture by providing a separate stack (called shadow stack) to store return addresses. Shadow stack can be protected using a reserved PTE encoding (PTE.W=1, PTE.R=0, PTE.X=0). Only shadow stack instructions can perform stores on shadow stack memory while regular stores on such memory result in access faults. Shadow stack memory can be read by regular load instructions. A new unprivileged csr `CSR_SSP` is introduced which holds pointer to shadow stack for the execution environment. To store return addresses on shadow stack, `sspush x1/x5` instruction is added. `sspopchk x1/x5` instruction pops from top of shadow stack and compares it with `x1/x5` and if there is a mismatch, cpu raises a software check exception. riscv-gnu-toolchain changes [2] are required to test these changes on qemu-user or on full blown linux guest using qemu-system. In order to test under qemu-system, one will require relevant linux changes as well. I've tested linux (6.8) based on current patches [3] and booted a rootfs compiled with cfi enabled toolchain to shell. There're still some work going on to make it work with VDSO and multi-label scheme. But none of those work is gate for these patches. I would like to express my sincere thanks to all the community members in helping out. Special shout out and acknowledgement to kito cheng, andy chiu, jim shu and jesse huang from SiFive. [1] - https://github.com/riscv/riscv-cfi [2] - https://github.com/sifive/riscv-gnu-toolchain/tree/cfi-dev [3] - https://lore.kernel.org/all/20240403234054.2020347-1-de...@rivosinc.com/ [4] - https://lore.kernel.org/all/20240709113652.1239-1-zhiwei_...@linux.alibaba.com/#t Deepak Gupta (24): target/riscv: Add zicfilp extension target/riscv: Introduce elp state and enabling controls for zicfilp target/riscv: save and restore elp state on priv transitions target/riscv: additional code information for sw check target/riscv: tracking indirect branches (fcfi) for zicfilp target/riscv: zicfilp `lpad` impl and branch tracking disas/riscv: enabled `lpad` disassembly linux-user/syscall: introduce prctl for indirect branch tracking linux-user/riscv: implement indirect branch tracking prctls target/riscv: Add zicfiss extension target/riscv: introduce ssp and enabling controls for zicfiss target/riscv: tb flag for shadow stack instructions target/riscv: implement zicfiss instructions target/riscv: compressed encodings for sspush and sspopchk target/riscv: mmu changes for zicfiss shadow stack protection target/riscv: shadow stack mmu index for shadow stack instructions linux-user/syscall: introduce prctl for shadow stack enable/disable linux-user/riscv: setup/teardown zicfiss shadow stack for qemu-user disas/riscv: enable disassembly for zicfiss instructions disas/riscv: enable disassembly for compressed sspush/sspopchk target/riscv: add trace-hooks for each case of sw-check exception linux-user: permit RISC-V CFI dynamic entry in VDSO linux-user: Add RISC-V zicfilp support in VDSO linux-user/riscv: Adding zicfiss/lp extension in hwprobe syscall disas/riscv.c | 71 +++++++++- disas/riscv.h | 4 + linux-user/gen-vdso-elfn.c.inc | 7 + linux-user/riscv/cpu_loop.c | 50 +++++++ linux-user/riscv/target_cpu.h | 7 + linux-user/riscv/target_prctl.h | 70 ++++++++++ linux-user/riscv/vdso-64.so | Bin 3944 -> 4128 bytes linux-user/riscv/vdso.S | 50 +++++++ linux-user/syscall.c | 40 ++++++ target/riscv/cpu.c | 21 +++ target/riscv/cpu.h | 28 ++++ target/riscv/cpu_bits.h | 23 ++++ target/riscv/cpu_cfg.h | 2 + target/riscv/cpu_helper.c | 166 +++++++++++++++++++++++- target/riscv/cpu_user.h | 1 + target/riscv/csr.c | 106 +++++++++++++++ target/riscv/helper.h | 6 + target/riscv/insn16.decode | 4 + target/riscv/insn32.decode | 23 +++- target/riscv/insn_trans/trans_rva.c.inc | 55 ++++++++ target/riscv/insn_trans/trans_rvi.c.inc | 52 ++++++++ target/riscv/internals.h | 4 + target/riscv/op_helper.c | 63 +++++++++ target/riscv/pmp.c | 5 + target/riscv/pmp.h | 3 +- target/riscv/tcg/tcg-cpu.c | 20 +++ target/riscv/trace-events | 6 + target/riscv/translate.c | 80 ++++++++++++ 28 files changed, 959 insertions(+), 8 deletions(-) -- 2.44.0