Message ID | 20181011151523.27101-7-yu-cheng.yu@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Control Flow Enforcement: Shadow Stack | expand |
That subject needs a verb: Subject: [PATCH v5 06/27] x86/cet: Add control protection exception handler On Thu, Oct 11, 2018 at 08:15:02AM -0700, Yu-cheng Yu wrote: > A control protection exception is triggered when a control flow transfer > attempt violated shadow stack or indirect branch tracking constraints. > For example, the return address for a RET instruction differs from the > safe copy on the shadow stack; or a JMP instruction arrives at a non- > ENDBR instruction. > > The control protection exception handler works in a similar way as the > general protection fault handler. > > Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com> > --- > arch/x86/entry/entry_64.S | 2 +- > arch/x86/include/asm/traps.h | 3 ++ > arch/x86/kernel/idt.c | 4 ++ > arch/x86/kernel/signal_compat.c | 2 +- > arch/x86/kernel/traps.c | 64 ++++++++++++++++++++++++++++++ > include/uapi/asm-generic/siginfo.h | 3 +- > 6 files changed, 75 insertions(+), 3 deletions(-) A *lot* of style problems here. Please use checkpatch and then common sense to check your patches before sending. All those below are valid, AFAICT: WARNING: function definition argument 'struct pt_regs *' should also have an identifier name #76: FILE: arch/x86/include/asm/traps.h:81: +dotraplinkage void do_control_protection(struct pt_regs *, long); WARNING: function definition argument 'long' should also have an identifier name #76: FILE: arch/x86/include/asm/traps.h:81: +dotraplinkage void do_control_protection(struct pt_regs *, long); WARNING: static const char * array should probably be static const char * const #124: FILE: arch/x86/kernel/traps.c:581: +static const char *control_protection_err[] = ERROR: that open brace { should be on the previous line #125: FILE: arch/x86/kernel/traps.c:582: +static const char *control_protection_err[] = +{ WARNING: quoted string split across lines #158: FILE: arch/x86/kernel/traps.c:615: + WARN_ONCE(1, "CET is disabled but got control " + "protection fault\n"); WARNING: Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit #165: FILE: arch/x86/kernel/traps.c:622: + printk_ratelimit()) { WARNING: Avoid logging continuation uses where feasible #176: FILE: arch/x86/kernel/traps.c:633: + pr_cont("\n"); ERROR: "(foo*)" should be "(foo *)" #183: FILE: arch/x86/kernel/traps.c:640: + info.si_addr = (void __user*)uprobe_get_trap_addr(regs); And now that patch doesn't even build anymore because of the siginfo changes which came in during the merge window. I guess I'll wait for your v6 patchset. --- arch/x86/kernel/traps.c: In function ‘do_control_protection’: arch/x86/kernel/traps.c:627:16: error: passing argument 1 of ‘clear_siginfo’ from incompatible pointer type [-Werror=incompatible-pointer-types] clear_siginfo(&info); ^~~~~ In file included from ./include/linux/sched/signal.h:6, from ./include/linux/ptrace.h:7, from ./include/linux/ftrace.h:14, from ./include/linux/kprobes.h:42, from arch/x86/kernel/traps.c:19: ./include/linux/signal.h:20:52: note: expected ‘kernel_siginfo_t *’ {aka ‘struct kernel_siginfo *’} but argument is of type ‘siginfo_t *’ {aka ‘struct siginfo *’} static inline void clear_siginfo(kernel_siginfo_t *info) ~~~~~~~~~~~~~~~~~~^~~~ arch/x86/kernel/traps.c:632:26: error: passing argument 2 of ‘force_sig_info’ from incompatible pointer type [-Werror=incompatible-pointer-types] force_sig_info(SIGSEGV, &info, tsk); ^~~~~ In file included from ./include/linux/ptrace.h:7, from ./include/linux/ftrace.h:14, from ./include/linux/kprobes.h:42, from arch/x86/kernel/traps.c:19: ./include/linux/sched/signal.h:327:32: note: expected ‘struct kernel_siginfo *’ but argument is of type ‘siginfo_t *’ {aka ‘struct siginfo *’} extern int force_sig_info(int, struct kernel_siginfo *, struct task_struct *); ^~~~~~~~~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors make[2]: *** [scripts/Makefile.build:291: arch/x86/kernel/traps.o] Error 1 make[1]: *** [scripts/Makefile.build:516: arch/x86/kernel] Error 2 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1060: arch/x86] Error 2 make: *** Waiting for unfinished jobs....
On Wed, 2018-11-14 at 19:44 +0100, Borislav Petkov wrote: > That subject needs a verb: > > Subject: [PATCH v5 06/27] x86/cet: Add control protection exception handler > > On Thu, Oct 11, 2018 at 08:15:02AM -0700, Yu-cheng Yu wrote: > > A control protection exception is triggered when a control flow transfer > > attempt violated shadow stack or indirect branch tracking constraints. > > For example, the return address for a RET instruction differs from the > > safe copy on the shadow stack; or a JMP instruction arrives at a non- > > ENDBR instruction. > > > > The control protection exception handler works in a similar way as the > > general protection fault handler. > > > > Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com> > > --- > > arch/x86/entry/entry_64.S | 2 +- > > arch/x86/include/asm/traps.h | 3 ++ > > arch/x86/kernel/idt.c | 4 ++ > > arch/x86/kernel/signal_compat.c | 2 +- > > arch/x86/kernel/traps.c | 64 ++++++++++++++++++++++++++++++ > > include/uapi/asm-generic/siginfo.h | 3 +- > > 6 files changed, 75 insertions(+), 3 deletions(-) > > A *lot* of style problems here. Please use checkpatch and then common > sense to check your patches before sending. All those below are valid, > AFAICT: > > WARNING: function definition argument 'struct pt_regs *' should also have an > identifier name > #76: FILE: arch/x86/include/asm/traps.h:81: > +dotraplinkage void do_control_protection(struct pt_regs *, long); > > WARNING: function definition argument 'long' should also have an identifier > name > #76: FILE: arch/x86/include/asm/traps.h:81: > +dotraplinkage void do_control_protection(struct pt_regs *, long); Yes, I was not sure if the addition should follow the existing style (which does not have identifier names). What do you think is right? Thanks, Yu-cheng
On Wed, Nov 14, 2018 at 12:19:42PM -0800, Yu-cheng Yu wrote: > Yes, I was not sure if the addition should follow the existing style (which does > not have identifier names). What do you think is right? Yeah, we've converted them all now to named params: https://git.kernel.org/tip/8e1599fcac2efda8b7d433ef69d2492f0b351e3f It probably would be easier if you redo your patchset ontop of current tip/master. Thx.
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 957dfb693ecc..5f4914e988df 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -1000,7 +1000,7 @@ idtentry spurious_interrupt_bug do_spurious_interrupt_bug has_error_code=0 idtentry coprocessor_error do_coprocessor_error has_error_code=0 idtentry alignment_check do_alignment_check has_error_code=1 idtentry simd_coprocessor_error do_simd_coprocessor_error has_error_code=0 - +idtentry control_protection do_control_protection has_error_code=1 /* * Reload gs selector with exception handling diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index 3de69330e6c5..5196050ff3d5 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -26,6 +26,7 @@ asmlinkage void invalid_TSS(void); asmlinkage void segment_not_present(void); asmlinkage void stack_segment(void); asmlinkage void general_protection(void); +asmlinkage void control_protection(void); asmlinkage void page_fault(void); asmlinkage void async_page_fault(void); asmlinkage void spurious_interrupt_bug(void); @@ -77,6 +78,7 @@ dotraplinkage void do_stack_segment(struct pt_regs *, long); dotraplinkage void do_double_fault(struct pt_regs *, long); #endif dotraplinkage void do_general_protection(struct pt_regs *, long); +dotraplinkage void do_control_protection(struct pt_regs *, long); dotraplinkage void do_page_fault(struct pt_regs *, unsigned long); dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *, long); dotraplinkage void do_coprocessor_error(struct pt_regs *, long); @@ -142,6 +144,7 @@ enum { X86_TRAP_AC, /* 17, Alignment Check */ X86_TRAP_MC, /* 18, Machine Check */ X86_TRAP_XF, /* 19, SIMD Floating-Point Exception */ + X86_TRAP_CP = 21, /* 21 Control Protection Fault */ X86_TRAP_IRET = 32, /* 32, IRET Exception */ }; diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index 01adea278a71..66ebc8cb16e2 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -104,6 +104,10 @@ static const __initconst struct idt_data def_idts[] = { #elif defined(CONFIG_X86_32) SYSG(IA32_SYSCALL_VECTOR, entry_INT80_32), #endif + +#ifdef CONFIG_X86_64 + INTG(X86_TRAP_CP, control_protection), +#endif }; /* diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c index 9ccbf0576cd0..c572a3de1037 100644 --- a/arch/x86/kernel/signal_compat.c +++ b/arch/x86/kernel/signal_compat.c @@ -27,7 +27,7 @@ static inline void signal_compat_build_tests(void) */ BUILD_BUG_ON(NSIGILL != 11); BUILD_BUG_ON(NSIGFPE != 15); - BUILD_BUG_ON(NSIGSEGV != 7); + BUILD_BUG_ON(NSIGSEGV != 8); BUILD_BUG_ON(NSIGBUS != 5); BUILD_BUG_ON(NSIGTRAP != 5); BUILD_BUG_ON(NSIGCHLD != 6); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index e6db475164ed..4188775681cf 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -578,6 +578,70 @@ do_general_protection(struct pt_regs *regs, long error_code) } NOKPROBE_SYMBOL(do_general_protection); +static const char *control_protection_err[] = +{ + "unknown", + "near-ret", + "far-ret/iret", + "endbranch", + "rstorssp", + "setssbsy", +}; + +/* + * When a control protection exception occurs, send a signal + * to the responsible application. Currently, control + * protection is only enabled for the user mode. This + * exception should not come from the kernel mode. + */ +dotraplinkage void +do_control_protection(struct pt_regs *regs, long error_code) +{ + struct task_struct *tsk; + siginfo_t info; + + RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); + if (notify_die(DIE_TRAP, "control protection fault", regs, + error_code, X86_TRAP_CP, SIGSEGV) == NOTIFY_STOP) + return; + cond_local_irq_enable(regs); + + if (!user_mode(regs)) + die("kernel control protection fault", regs, error_code); + + if (!static_cpu_has(X86_FEATURE_SHSTK) && + !static_cpu_has(X86_FEATURE_IBT)) + WARN_ONCE(1, "CET is disabled but got control " + "protection fault\n"); + + tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_nr = X86_TRAP_CP; + + if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && + printk_ratelimit()) { + unsigned int max_err; + + max_err = ARRAY_SIZE(control_protection_err) - 1; + if ((error_code < 0) || (error_code > max_err)) + error_code = 0; + pr_info("%s[%d] control protection ip:%lx sp:%lx error:%lx(%s)", + tsk->comm, task_pid_nr(tsk), + regs->ip, regs->sp, error_code, + control_protection_err[error_code]); + print_vma_addr(KERN_CONT " in ", regs->ip); + pr_cont("\n"); + } + + clear_siginfo(&info); + info.si_signo = SIGSEGV; + info.si_errno = error_code; + info.si_code = SEGV_CPERR; + info.si_addr = (void __user*)uprobe_get_trap_addr(regs); + force_sig_info(SIGSEGV, &info, tsk); +} +NOKPROBE_SYMBOL(do_control_protection); + dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) { #ifdef CONFIG_DYNAMIC_FTRACE diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index 80e2a7227205..264d8e03270f 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -228,7 +228,8 @@ typedef struct siginfo { #define SEGV_ACCADI 5 /* ADI not enabled for mapped object */ #define SEGV_ADIDERR 6 /* Disrupting MCD error */ #define SEGV_ADIPERR 7 /* Precise MCD exception */ -#define NSIGSEGV 7 +#define SEGV_CPERR 8 +#define NSIGSEGV 8 /* * SIGBUS si_codes
A control protection exception is triggered when a control flow transfer attempt violated shadow stack or indirect branch tracking constraints. For example, the return address for a RET instruction differs from the safe copy on the shadow stack; or a JMP instruction arrives at a non- ENDBR instruction. The control protection exception handler works in a similar way as the general protection fault handler. Signed-off-by: Yu-cheng Yu <yu-cheng.yu@intel.com> --- arch/x86/entry/entry_64.S | 2 +- arch/x86/include/asm/traps.h | 3 ++ arch/x86/kernel/idt.c | 4 ++ arch/x86/kernel/signal_compat.c | 2 +- arch/x86/kernel/traps.c | 64 ++++++++++++++++++++++++++++++ include/uapi/asm-generic/siginfo.h | 3 +- 6 files changed, 75 insertions(+), 3 deletions(-)