diff options
author | Oleg Nesterov <oleg@redhat.com> | 2014-04-03 14:20:10 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2014-04-17 15:58:20 -0400 |
commit | 014940bad8e46ca7bd0483f760f9cba60088a3d4 (patch) | |
tree | cbefdeb0f0d2b84f7609313f28fdf460c42dfaac | |
parent | e55848a4f8ee52465771983e144f0c3337776eda (diff) |
uprobes/x86: Send SIGILL if arch_uprobe_post_xol() fails
Currently the error from arch_uprobe_post_xol() is silently ignored.
This doesn't look good and this can lead to the hard-to-debug problems.
1. Change handle_singlestep() to loudly complain and send SIGILL.
Note: this only affects x86, ppc/arm can't fail.
2. Change arch_uprobe_post_xol() to call arch_uprobe_abort_xol() and
avoid TF games if it is going to return an error.
This can help to to analyze the problem, if nothing else we should
not report ->ip = xol_slot in the core-file.
Note: this means that handle_riprel_post_xol() can be called twice,
but this is fine because it is idempotent.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Reviewed-by: Jim Keniston <jkenisto@us.ibm.com>
-rw-r--r-- | arch/x86/kernel/uprobes.c | 16 | ||||
-rw-r--r-- | kernel/events/uprobes.c | 8 |
2 files changed, 19 insertions, 5 deletions
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 08cdb82815fe..e72903eacd43 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -594,6 +594,15 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
594 | struct uprobe_task *utask = current->utask; | 594 | struct uprobe_task *utask = current->utask; |
595 | 595 | ||
596 | WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); | 596 | WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); |
597 | |||
598 | if (auprobe->ops->post_xol) { | ||
599 | int err = auprobe->ops->post_xol(auprobe, regs); | ||
600 | if (err) { | ||
601 | arch_uprobe_abort_xol(auprobe, regs); | ||
602 | return err; | ||
603 | } | ||
604 | } | ||
605 | |||
597 | current->thread.trap_nr = utask->autask.saved_trap_nr; | 606 | current->thread.trap_nr = utask->autask.saved_trap_nr; |
598 | /* | 607 | /* |
599 | * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP | 608 | * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP |
@@ -605,8 +614,6 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
605 | else if (!(auprobe->fixups & UPROBE_FIX_SETF)) | 614 | else if (!(auprobe->fixups & UPROBE_FIX_SETF)) |
606 | regs->flags &= ~X86_EFLAGS_TF; | 615 | regs->flags &= ~X86_EFLAGS_TF; |
607 | 616 | ||
608 | if (auprobe->ops->post_xol) | ||
609 | return auprobe->ops->post_xol(auprobe, regs); | ||
610 | return 0; | 617 | return 0; |
611 | } | 618 | } |
612 | 619 | ||
@@ -641,8 +648,9 @@ int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, | |||
641 | 648 | ||
642 | /* | 649 | /* |
643 | * This function gets called when XOL instruction either gets trapped or | 650 | * This function gets called when XOL instruction either gets trapped or |
644 | * the thread has a fatal signal, so reset the instruction pointer to its | 651 | * the thread has a fatal signal, or if arch_uprobe_post_xol() failed. |
645 | * probed address. | 652 | * Reset the instruction pointer to its probed address for the potential |
653 | * restart or for post mortem analysis. | ||
646 | */ | 654 | */ |
647 | void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | 655 | void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) |
648 | { | 656 | { |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index ea2a7c0728bb..d1edc5e6fd03 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -1867,10 +1867,11 @@ out: | |||
1867 | static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) | 1867 | static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) |
1868 | { | 1868 | { |
1869 | struct uprobe *uprobe; | 1869 | struct uprobe *uprobe; |
1870 | int err = 0; | ||
1870 | 1871 | ||
1871 | uprobe = utask->active_uprobe; | 1872 | uprobe = utask->active_uprobe; |
1872 | if (utask->state == UTASK_SSTEP_ACK) | 1873 | if (utask->state == UTASK_SSTEP_ACK) |
1873 | arch_uprobe_post_xol(&uprobe->arch, regs); | 1874 | err = arch_uprobe_post_xol(&uprobe->arch, regs); |
1874 | else if (utask->state == UTASK_SSTEP_TRAPPED) | 1875 | else if (utask->state == UTASK_SSTEP_TRAPPED) |
1875 | arch_uprobe_abort_xol(&uprobe->arch, regs); | 1876 | arch_uprobe_abort_xol(&uprobe->arch, regs); |
1876 | else | 1877 | else |
@@ -1884,6 +1885,11 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) | |||
1884 | spin_lock_irq(¤t->sighand->siglock); | 1885 | spin_lock_irq(¤t->sighand->siglock); |
1885 | recalc_sigpending(); /* see uprobe_deny_signal() */ | 1886 | recalc_sigpending(); /* see uprobe_deny_signal() */ |
1886 | spin_unlock_irq(¤t->sighand->siglock); | 1887 | spin_unlock_irq(¤t->sighand->siglock); |
1888 | |||
1889 | if (unlikely(err)) { | ||
1890 | uprobe_warn(current, "execute the probed insn, sending SIGILL."); | ||
1891 | force_sig_info(SIGILL, SEND_SIG_FORCED, current); | ||
1892 | } | ||
1887 | } | 1893 | } |
1888 | 1894 | ||
1889 | /* | 1895 | /* |