summaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/uprobes.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2014-04-24 19:21:38 +0200
committerOleg Nesterov <oleg@redhat.com>2014-04-30 19:10:38 +0200
commit2b82cadffc4154a25c25d88a63c7fb3397cda9d6 (patch)
tree05f8ea13caaf1fdd84adf154d0bd33b63cb27220 /arch/x86/kernel/uprobes.c
parentuprobes/x86: Cleanup the usage of arch_uprobe->def.fixups, make it u8 (diff)
downloadlinux-2b82cadffc4154a25c25d88a63c7fb3397cda9d6.tar.xz
linux-2b82cadffc4154a25c25d88a63c7fb3397cda9d6.zip
uprobes/x86: Introduce push_ret_address()
Extract the "push return address" code from branch_emulate_op() into the new simple helper, push_ret_address(). It will have more users. Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'arch/x86/kernel/uprobes.c')
-rw-r--r--arch/x86/kernel/uprobes.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index a8e1d7e47001..df75913acfc0 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -407,6 +407,17 @@ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
return 0;
}
+static int push_ret_address(struct pt_regs *regs, unsigned long ip)
+{
+ unsigned long new_sp = regs->sp - sizeof_long();
+
+ if (copy_to_user((void __user *)new_sp, &ip, sizeof_long()))
+ return -EFAULT;
+
+ regs->sp = new_sp;
+ return 0;
+}
+
/*
* Adjust the return address pushed by a call insn executed out of line.
*/
@@ -517,7 +528,6 @@ static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
unsigned long offs = (long)auprobe->branch.offs;
if (branch_is_call(auprobe)) {
- unsigned long new_sp = regs->sp - sizeof_long();
/*
* If it fails we execute this (mangled, see the comment in
* branch_clear_offset) insn out-of-line. In the likely case
@@ -527,9 +537,8 @@ static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
*
* But there is corner case, see the comment in ->post_xol().
*/
- if (copy_to_user((void __user *)new_sp, &new_ip, sizeof_long()))
+ if (push_ret_address(regs, new_ip))
return false;
- regs->sp = new_sp;
} else if (!check_jmp_cond(auprobe, regs)) {
offs = 0;
}