aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2014-05-12 12:24:45 -0400
committerOleg Nesterov <oleg@redhat.com>2014-05-14 07:57:28 -0400
commitb02ef20a9fba08948e643d3eec0efadf1da01a44 (patch)
treed0db097668940dce698fec8b00d228cd29c1dee0 /arch/x86
parent0eb14833d5b1ea1accfeffb71be5de5929f85da9 (diff)
uprobes/x86: Fix the wrong ->si_addr when xol triggers a trap
If the probed insn triggers a trap, ->si_addr = regs->ip is technically correct, but this is not what the signal handler wants; we need to pass the address of the probed insn, not the address of xol slot. Add the new arch-agnostic helper, uprobe_get_trap_addr(), and change fill_trap_info() and math_error() to use it. !CONFIG_UPROBES case in uprobes.h uses a macro to avoid include hell and ensure that it can be compiled even if an architecture doesn't define instruction_pointer(). Test-case: #include <signal.h> #include <stdio.h> #include <unistd.h> extern void probe_div(void); void sigh(int sig, siginfo_t *info, void *c) { int passed = (info->si_addr == probe_div); printf(passed ? "PASS\n" : "FAIL\n"); _exit(!passed); } int main(void) { struct sigaction sa = { .sa_sigaction = sigh, .sa_flags = SA_SIGINFO, }; sigaction(SIGFPE, &sa, NULL); asm ( "xor %ecx,%ecx\n" ".globl probe_div; probe_div:\n" "idiv %ecx\n" ); return 0; } it fails if probe_div() is probed. Note: show_unhandled_signals users should probably use this helper too, but we need to cleanup them first. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/traps.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 73b3ea32245a..3fdb20548c4b 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -23,6 +23,7 @@
23#include <linux/kernel.h> 23#include <linux/kernel.h>
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/ptrace.h> 25#include <linux/ptrace.h>
26#include <linux/uprobes.h>
26#include <linux/string.h> 27#include <linux/string.h>
27#include <linux/delay.h> 28#include <linux/delay.h>
28#include <linux/errno.h> 29#include <linux/errno.h>
@@ -148,11 +149,11 @@ static siginfo_t *fill_trap_info(struct pt_regs *regs, int signr, int trapnr,
148 149
149 case X86_TRAP_DE: 150 case X86_TRAP_DE:
150 sicode = FPE_INTDIV; 151 sicode = FPE_INTDIV;
151 siaddr = regs->ip; 152 siaddr = uprobe_get_trap_addr(regs);
152 break; 153 break;
153 case X86_TRAP_UD: 154 case X86_TRAP_UD:
154 sicode = ILL_ILLOPN; 155 sicode = ILL_ILLOPN;
155 siaddr = regs->ip; 156 siaddr = uprobe_get_trap_addr(regs);
156 break; 157 break;
157 case X86_TRAP_AC: 158 case X86_TRAP_AC:
158 sicode = BUS_ADRALN; 159 sicode = BUS_ADRALN;
@@ -531,7 +532,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
531 task->thread.error_code = error_code; 532 task->thread.error_code = error_code;
532 info.si_signo = SIGFPE; 533 info.si_signo = SIGFPE;
533 info.si_errno = 0; 534 info.si_errno = 0;
534 info.si_addr = (void __user *)regs->ip; 535 info.si_addr = (void __user *)uprobe_get_trap_addr(regs);
535 if (trapnr == X86_TRAP_MF) { 536 if (trapnr == X86_TRAP_MF) {
536 unsigned short cwd, swd; 537 unsigned short cwd, swd;
537 /* 538 /*