mbox series

[00/24] riscv support for control flow integrity extensions

Message ID 20240725234614.3850142-1-debug@rivosinc.com (mailing list archive)
Headers show
Series riscv support for control flow integrity extensions | expand

Message

Deepak Gupta July 25, 2024, 11:45 p.m. UTC
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-debug@rivosinc.com/
[4] - https://lore.kernel.org/all/20240709113652.1239-1-zhiwei_liu@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(-)