[RFC] powerpc/uprobes: Fixup si_addr if we took an exception while single stepping
diff mbox series

Message ID 20170913200330.15606-1-naveen.n.rao@linux.vnet.ibm.com
State New
Headers show
Series
  • [RFC] powerpc/uprobes: Fixup si_addr if we took an exception while single stepping
Related show

Commit Message

Naveen N. Rao Sept. 13, 2017, 8:03 p.m. UTC
If the single-stepped instruction causes an exception, we may end up
setting siginfo.si_addr to the address of the uprobe xol area. This is
not desirable since the address won't make sense for the process if it
wants to handle the exception. Fixup the si_addr field in such cases.

Reported-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/uprobes.h |  7 +++++++
 arch/powerpc/kernel/traps.c        |  4 ++++
 arch/powerpc/kernel/uprobes.c      | 17 +++++++++++++++++
 3 files changed, 28 insertions(+)

Patch
diff mbox series

diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h
index 7422a999a39a..13fc6af3c1fd 100644
--- a/arch/powerpc/include/asm/uprobes.h
+++ b/arch/powerpc/include/asm/uprobes.h
@@ -23,6 +23,7 @@ 
  */
 
 #include <linux/notifier.h>
+#include <asm/siginfo.h>
 #include <asm/probes.h>
 
 typedef ppc_opcode_t uprobe_opcode_t;
@@ -45,4 +46,10 @@  struct arch_uprobe_task {
 	unsigned long	saved_trap_nr;
 };
 
+#ifdef CONFIG_UPROBES
+extern void uprobe_fixup_exception(struct pt_regs *regs, siginfo_t *info);
+#else
+static inline void uprobe_fixup_exception(struct pt_regs *regs, siginfo_t *info) { }
+#endif
+
 #endif	/* _ASM_UPROBES_H */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index ec74e203ee04..1bb858a37029 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -66,6 +66,7 @@ 
 #include <asm/hmi.h>
 #include <sysdev/fsl_pci.h>
 #include <asm/kprobes.h>
+#include <asm/uprobes.h>
 
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC_CORE)
 int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -292,6 +293,9 @@  void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 	info.si_signo = signr;
 	info.si_code = code;
 	info.si_addr = (void __user *) addr;
+
+	uprobe_fixup_exception(regs, &info);
+
 	force_sig_info(signr, &info, current);
 }
 
diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c
index 5d105b8eeece..a361a56e6210 100644
--- a/arch/powerpc/kernel/uprobes.c
+++ b/arch/powerpc/kernel/uprobes.c
@@ -25,6 +25,7 @@ 
 #include <linux/uprobes.h>
 #include <linux/uaccess.h>
 #include <linux/kdebug.h>
+#include <linux/signal.h>
 
 #include <asm/sstep.h>
 
@@ -214,3 +215,19 @@  bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
 	else
 		return regs->gpr[1] < ret->stack;
 }
+
+void uprobe_fixup_exception(struct pt_regs *regs, siginfo_t *info)
+{
+	struct task_struct *t = current;
+	struct uprobe_task *utask = t->utask;
+
+	if (likely(!utask || !utask->active_uprobe))
+		return;
+
+	/*
+	 * We reset si_addr here.
+	 * regs->nip is reset during our way back through uprobe_deny_signal()
+	 */
+	if (info->si_addr == (void __user *) utask->xol_vaddr)
+		info->si_addr = (void __user *) utask->vaddr;
+}