Skip to content

Commit 9d42fc2

Browse files
deepak0414Paul Walmsley
authored andcommitted
riscv/traps: Introduce software check exception and uprobe handling
The Zicfiss and Zicfilp extensions introduce a new exception, the 'software check exception', in the privileged ISA, with cause code = 18. This patch implements support for software check exceptions. Additionally, the patch implements a CFI violation handler which checks the code in the xtval register. If xtval=2, the software check exception happened because of an indirect branch that didn't land on a 4 byte aligned PC or on a 'lpad' instruction, or the label value embedded in 'lpad' didn't match the label value set in the x7 register. If xtval=3, the software check exception happened due to a mismatch between the link register (x1 or x5) and the top of shadow stack (on execution of `sspopchk`). In case of a CFI violation, SIGSEGV is raised with code=SEGV_CPERR. SEGV_CPERR was introduced by the x86 shadow stack patches. To keep uprobes working, handle the uprobe event first before reporting the CFI violation in the software check exception handler. This is because, when the landing pad is activated, if the uprobe point is set at the lpad instruction at the beginning of a function, the system triggers a software check exception instead of an ebreak exception due to the exception priority. This would prevent uprobe from working. Reviewed-by: Zong Li <zong.li@sifive.com> Co-developed-by: Zong Li <zong.li@sifive.com> Signed-off-by: Zong Li <zong.li@sifive.com> Signed-off-by: Deepak Gupta <debug@rivosinc.com> Tested-by: Andreas Korb <andreas.korb@aisec.fraunhofer.de> # QEMU, custom CVA6 Tested-by: Valentin Haudiquet <valentin.haudiquet@canonical.com> Link: https://patch.msgid.link/20251112-v5_user_cfi_series-v23-15-b55691eacf4f@rivosinc.com [pjw@kernel.org: cleaned up the patch description] Signed-off-by: Paul Walmsley <pjw@kernel.org>
1 parent 8a9e22d commit 9d42fc2

4 files changed

Lines changed: 60 additions & 0 deletions

File tree

arch/riscv/include/asm/asm-prototypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ DECLARE_DO_ERROR_INFO(do_trap_ecall_u);
5151
DECLARE_DO_ERROR_INFO(do_trap_ecall_s);
5252
DECLARE_DO_ERROR_INFO(do_trap_ecall_m);
5353
DECLARE_DO_ERROR_INFO(do_trap_break);
54+
DECLARE_DO_ERROR_INFO(do_trap_software_check);
5455

5556
asmlinkage void ret_from_fork_kernel(void *fn_arg, int (*fn)(void *), struct pt_regs *regs);
5657
asmlinkage void ret_from_fork_user(struct pt_regs *regs);

arch/riscv/include/asm/entry-common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,6 @@ static inline int handle_misaligned_store(struct pt_regs *regs)
4040
}
4141
#endif
4242

43+
bool handle_user_cfi_violation(struct pt_regs *regs);
44+
4345
#endif /* _ASM_RISCV_ENTRY_COMMON_H */

arch/riscv/kernel/entry.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,9 @@ SYM_DATA_START_LOCAL(excp_vect_table)
495495
RISCV_PTR do_page_fault /* load page fault */
496496
RISCV_PTR do_trap_unknown
497497
RISCV_PTR do_page_fault /* store page fault */
498+
RISCV_PTR do_trap_unknown /* cause=16 */
499+
RISCV_PTR do_trap_unknown /* cause=17 */
500+
RISCV_PTR do_trap_software_check /* cause=18 is sw check exception */
498501
SYM_DATA_END_LABEL(excp_vect_table, SYM_L_LOCAL, excp_vect_table_end)
499502

500503
#ifndef CONFIG_MMU

arch/riscv/kernel/traps.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,60 @@ void do_trap_ecall_u(struct pt_regs *regs)
368368

369369
}
370370

371+
#define CFI_TVAL_FCFI_CODE 2
372+
#define CFI_TVAL_BCFI_CODE 3
373+
/* handle cfi violations */
374+
bool handle_user_cfi_violation(struct pt_regs *regs)
375+
{
376+
unsigned long tval = csr_read(CSR_TVAL);
377+
bool is_fcfi = (tval == CFI_TVAL_FCFI_CODE && cpu_supports_indirect_br_lp_instr());
378+
bool is_bcfi = (tval == CFI_TVAL_BCFI_CODE && cpu_supports_shadow_stack());
379+
380+
/*
381+
* Handle uprobe event first. The probe point can be a valid target
382+
* of indirect jumps or calls, in this case, forward cfi violation
383+
* will be triggered instead of breakpoint exception. Clear ELP flag
384+
* on sstatus image as well to avoid recurring fault.
385+
*/
386+
if (is_fcfi && probe_breakpoint_handler(regs)) {
387+
regs->status &= ~SR_ELP;
388+
return true;
389+
}
390+
391+
if (is_fcfi || is_bcfi) {
392+
do_trap_error(regs, SIGSEGV, SEGV_CPERR, regs->epc,
393+
"Oops - control flow violation");
394+
return true;
395+
}
396+
397+
return false;
398+
}
399+
400+
/*
401+
* software check exception is defined with risc-v cfi spec. Software check
402+
* exception is raised when:
403+
* a) An indirect branch doesn't land on 4 byte aligned PC or `lpad`
404+
* instruction or `label` value programmed in `lpad` instr doesn't
405+
* match with value setup in `x7`. reported code in `xtval` is 2.
406+
* b) `sspopchk` instruction finds a mismatch between top of shadow stack (ssp)
407+
* and x1/x5. reported code in `xtval` is 3.
408+
*/
409+
asmlinkage __visible __trap_section void do_trap_software_check(struct pt_regs *regs)
410+
{
411+
if (user_mode(regs)) {
412+
irqentry_enter_from_user_mode(regs);
413+
414+
/* not a cfi violation, then merge into flow of unknown trap handler */
415+
if (!handle_user_cfi_violation(regs))
416+
do_trap_unknown(regs);
417+
418+
irqentry_exit_to_user_mode(regs);
419+
} else {
420+
/* sw check exception coming from kernel is a bug in kernel */
421+
die(regs, "Kernel BUG");
422+
}
423+
}
424+
371425
#ifdef CONFIG_MMU
372426
asmlinkage __visible noinstr void do_page_fault(struct pt_regs *regs)
373427
{

0 commit comments

Comments
 (0)