From e1e55379f2ed82eb16cebc95fcd95162285ea74e Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Tue, 7 Jul 2015 23:38:27 -0400 Subject: [PATCH] dtrace: ignore any and all PFs during NOFAULT memory acceses Previously, memory access from DTrace probe handling could be marked as NOFAULT (ignore faults) and/or NOPF (ignore page faults). However, when safe memory access support is necessary, it is required that no faults of any kind are allowed to disrupt the system. Signed-off-by: Kris Van Hees Acked-by: Nick Alcock --- arch/sparc/kernel/dtrace_util.c | 25 +++++++++++++------------ include/linux/dtrace_os.h | 9 ++++++--- kernel/dtrace/dtrace_os.c | 14 -------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/arch/sparc/kernel/dtrace_util.c b/arch/sparc/kernel/dtrace_util.c index 4c3126c99cea..cd68baf37acf 100644 --- a/arch/sparc/kernel/dtrace_util.c +++ b/arch/sparc/kernel/dtrace_util.c @@ -11,11 +11,20 @@ #include #include -void dtrace_skip_instruction(struct pt_regs *regs) { +void dtrace_skip_instruction(struct pt_regs *regs) +{ regs->tpc = regs->tnpc; regs->tnpc += 4; } +void dtrace_handle_badaddr(struct pt_regs *regs) { + unsigned long addr = current_thread_info()->fault_address; + + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + this_cpu_core->cpuc_dtrace_illval = addr; + + dtrace_skip_instruction(regs); +} int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, void *args) @@ -24,15 +33,10 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, switch (val) { case DIE_PAGE_FAULT: { - unsigned long addr = current_thread_info()->fault_address; - if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) return NOTIFY_DONE; - DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); - this_cpu_core->cpuc_dtrace_illval = addr; - - dtrace_skip_instruction(dargs->regs); + dtrace_handle_badaddr(dargs->regs); return NOTIFY_OK | NOTIFY_STOP_MASK; } @@ -47,16 +51,13 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, return NOTIFY_OK | NOTIFY_STOP_MASK; } case DIE_TRAP: { - unsigned long addr = current_thread_info()->fault_address; - if (dargs->trapnr != 0x34) return NOTIFY_DONE; + if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) return NOTIFY_DONE; - DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); - - dtrace_skip_instruction(dargs->regs); + dtrace_handle_badaddr(dargs->regs); return NOTIFY_OK | NOTIFY_STOP_MASK; } diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h index 74fa48609c36..8c7819ae55c8 100644 --- a/include/linux/dtrace_os.h +++ b/include/linux/dtrace_os.h @@ -60,7 +60,7 @@ typedef struct stacktrace_state { } stacktrace_state_t; extern void dtrace_stacktrace(stacktrace_state_t *); -extern int dtrace_handle_no_pf(struct pt_regs *); +extern void dtrace_handle_badaddr(struct pt_regs *); /* * This is only safe to call if we know this is a userspace fault @@ -68,8 +68,11 @@ extern int dtrace_handle_no_pf(struct pt_regs *); */ static inline int dtrace_no_pf(struct pt_regs *regs) { - if (unlikely(DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOPF))) - return dtrace_handle_no_pf(regs); + if (unlikely(DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT))) { + dtrace_handle_badaddr(regs); + return 1; + } + return 0; } diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index 06d9498d44e8..415967fd5680 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -443,20 +443,6 @@ void dtrace_disable(void) } EXPORT_SYMBOL(dtrace_disable); -/* - * The dtrace-is-active body of dtrace_no_pf(), split into a separate function - * to keep icache pressure down while incurring function call overhead only in - * the rare dtrace-active, pf-disabled case. - */ -int dtrace_handle_no_pf(struct pt_regs *regs) -{ - DTRACE_CPUFLAG_SET(CPU_DTRACE_PF_TRAPPED); - - dtrace_skip_instruction(regs); - - return 1; -} - /*---------------------------------------------------------------------------*\ (* USER SPACE TRACING (FASTTRAP) SUPPORT *) \*---------------------------------------------------------------------------*/ -- 2.50.1