Still learning to use git send-mail. Hopefully this time cover-letter also reaches everyone.
I am sending this patch series as RFC for an extension which helps software enforce control-flow integrity (cfi) on riscv CPUs. Currently spec is called zisslpcfi spec - https://github.com/riscv/riscv-cfi. This literally means "unprivileged integer shadow stack & landing pad based cfi". Sending this as RFC because - Even though I dont expect major change in zimops, it's still on the stove. - zisslpcfi is tied up nicely still being worked on. - I would like eyeballing on indirect branch tracking implementation. zisslpcfi (CFI) extends ISA in following manner: Forward cfi (indirect call/jmp) - Landing pad instruction requirement for indirect call/jmp All indirect call and jump must land on landing pad instruction `lpcll` else CPU will raise illegal instruction exception. `lpcll` stands for land pad check lower label. - Static label (25bit label) checking instructions for indirect call/jmp Extension provides mechanism using which a compiler generated label value can be set in a designated CSR at call site and it can be checked at the call target. If mismatch happens, CPU will raise illegal instruction exception. Compiler can generate hash based on function signature type. Extension provide mechanisms using which label value is part of the instruction itself as immediate and thus has static immutable property. Backward cfi (returns) - Shadow stack (SS) for function returns Extension provides sspush x1/x5, sspop x1/x5 and sschkra instructions. sspush will push on shadow stack while sspop will pop from shadow stack sschkra will succeed only when x1 == x5 is true else it will raise illegal instruction exception. Shadow stacks introduces new virtual memory type and thus new PTE encodings. Existing reserved encoding of R=0,W=1,X=0 is now shadow stack PTE encoding (only if backward cfi is enabled for current mode). New virtual memory type allows CPU to distinguish so that stores coming from sspush or ssamoswap can succeed while regular stores raise access violations. opcodes: zisslpcfi opcodes are carved out of new opcode encodings. These opcodes encodings were reserved until now. A new extension called zimops make these opcodes into "may be operations". zimops stands for unprivileged may be operations (mops) and if implemented default behavior is to mov 0 to rd. zisslpcfi extension changes executable in a way where it should be able to run on riscv cpu which implements cfi extension as well as riscv cpu which doesn't implement cfi extension. As long as zimops is implemented, all such instructions will not fault and simply move 0 to rd. A hart implementing cfi must implement zimops. Any future extension can re-purpose zimops to change behavior and claim them while also not breaking binary/executable compatiblity . zisslpcfi is first such extension to modify zimops behavior. Instructions: zisslpcfi defines following instructions. Backward control flow ********************* sspush x1/x5: Decrement shadow stack pointer and pushes x1 or x5 on shadow stack. sspop x1/x5: Pops from shadow stack into x1 or x5. Increments shadow stack pointer. ssprr: Reads current shadow stack pointer into a destination register. sschckra: Compares x1 with x5. Raises illegal instr exception if x1 != x5. ssamoswap: Atomically swaps value on top of shadow stack. Forward control flow ******************** Forward control flow extends architecture to allow software to set labels (25bits of label) at call/jmp site and check labels at target. Extension gives instructions to set label as part of immediate in instruction itself . Since immediate is limited in terms of bit length, labels are set and checked in ladder fashion of 9, 8 and 8 bits. lpsll, lpsml, lpsul: sets lower (9bit), mid (8bit) and upper (8bit) label values in CSR_LPLR respectively. lpcll, lpcml, lpcul: checks lower (9bit), mid (8bit) and upper (8bit) label values with CSR_LPLR respectively. Check label instructions raise illegal instruction fault when labels mismatch. `lpcll` has dual purpose; it acts as landing pad instruction as well label checking for lower 9 bits. More on shadow stack ******************** Shadow stacks have new encodings (R=0,W=1,X=0) in first level page tables to ensure they can be writeable only via special shadow stack management instructions and regular stores are disallowed. Regular stores on shadow stack memory raise AMO/store access fault. Shadow stack load (sspop) on non-shadow stack memory raise load access fault. Shadow stack store (sspush) on non-shadow stack memory raise store access fault. To provide each mode their own shadow stack translations, this implementation flushes shadow stack translations on privilege change and thus each mode keep their own translation as long as mode doesn't change. Shadow stack accesses need to coexist with normal accesses, but have different permission checks. Since hypervisor access instructions and shadow stack accesses are mutually exclusive (both use dedicated instructions), they don't need independent bits in the MMU index assignments. Tests and other bits ******************** For convenience this patch is based on below qemu branch https://github.com/deepak0414/qemu/tree/scfi_menvcfg_gh_Zisslpcfi-0.1 I've been able to boot linux kernel using this implementation and run test apps. Kernel branch I am using is below https://github.com/deepak0414/linux-riscv-cfi/tree/Zisslpcfi-0.4_v6.1-rc2 In order to perform unit-tests, I've been using riscv-test and created unit tests to test implementation. riscv-tests branch URL is below https://github.com/deepak0414/riscv-tests/tree/cfi_tests Deepak Gupta (9): target/riscv: adding zimops and zisslpcfi extension to RISCV cpu config target/riscv: zisslpcfi CSR, bit positions and other definitions target/riscv: implements CSRs and new bits in existing CSRs in zisslpcfi target/riscv: helper functions for forward and backward cfi target/riscv: state save and restore of zisslppcfi state target/riscv: MMU changes for back cfi's shadow stack target/riscv: Tracking indirect branches (fcfi) using TCG target/riscv: Instructions encodings, implementation and handlers target/riscv: diassembly support for zisslpcfi instructions disas/riscv.c | 127 ++++++- target/riscv/cpu-param.h | 1 + target/riscv/cpu.c | 15 + target/riscv/cpu.h | 15 + target/riscv/cpu_bits.h | 40 +++ target/riscv/cpu_helper.c | 196 +++++++++-- target/riscv/csr.c | 137 +++++++- target/riscv/helper.h | 7 + target/riscv/insn32.decode | 29 ++ target/riscv/insn_trans/trans_rvi.c.inc | 14 + target/riscv/insn_trans/trans_zimops.c.inc | 53 +++ target/riscv/insn_trans/trans_zisslpcfi.c.inc | 310 ++++++++++++++++++ target/riscv/op_helper.c | 79 +++++ target/riscv/pmp.c | 9 + target/riscv/pmp.h | 3 +- target/riscv/translate.c | 54 +++ 16 files changed, 1067 insertions(+), 22 deletions(-) create mode 100644 target/riscv/insn_trans/trans_zimops.c.inc create mode 100644 target/riscv/insn_trans/trans_zisslpcfi.c.inc -- 2.25.1