diff options
author | Oleg Nesterov <oleg@redhat.com> | 2015-07-21 09:40:08 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-07-31 04:38:03 -0400 |
commit | 0b5256c7f173258b19d98364adb57f707dda22f3 (patch) | |
tree | abc5d9b982f73c133235fd7e955e29780f8c8c69 /kernel/events | |
parent | 2bb5e840e873f8778a41801141771f54f547fa65 (diff) |
uprobes: Send SIGILL if handle_trampoline() fails
1. It doesn't make sense to continue if handle_trampoline()
fails, change handle_swbp() to always return after this call.
2. Turn pr_warn() into uprobe_warn(), and change
handle_trampoline() to send SIGILL on failure. It is pointless to
return to user mode with the corrupted instruction_pointer() which
we can't restore.
Tested-by: Pratyush Anand <panand@redhat.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Acked-by: Anton Arapov <arapov@gmail.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20150721134008.GA4745@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
-rw-r--r-- | kernel/events/uprobes.c | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index d8c702fc836f..eabdc21366ee 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -1770,7 +1770,7 @@ handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs) | |||
1770 | up_read(&uprobe->register_rwsem); | 1770 | up_read(&uprobe->register_rwsem); |
1771 | } | 1771 | } |
1772 | 1772 | ||
1773 | static bool handle_trampoline(struct pt_regs *regs) | 1773 | static void handle_trampoline(struct pt_regs *regs) |
1774 | { | 1774 | { |
1775 | struct uprobe_task *utask; | 1775 | struct uprobe_task *utask; |
1776 | struct return_instance *ri; | 1776 | struct return_instance *ri; |
@@ -1778,11 +1778,11 @@ static bool handle_trampoline(struct pt_regs *regs) | |||
1778 | 1778 | ||
1779 | utask = current->utask; | 1779 | utask = current->utask; |
1780 | if (!utask) | 1780 | if (!utask) |
1781 | return false; | 1781 | goto sigill; |
1782 | 1782 | ||
1783 | ri = utask->return_instances; | 1783 | ri = utask->return_instances; |
1784 | if (!ri) | 1784 | if (!ri) |
1785 | return false; | 1785 | goto sigill; |
1786 | 1786 | ||
1787 | /* | 1787 | /* |
1788 | * TODO: we should throw out return_instance's invalidated by | 1788 | * TODO: we should throw out return_instance's invalidated by |
@@ -1804,8 +1804,12 @@ static bool handle_trampoline(struct pt_regs *regs) | |||
1804 | } | 1804 | } |
1805 | 1805 | ||
1806 | utask->return_instances = ri; | 1806 | utask->return_instances = ri; |
1807 | return; | ||
1808 | |||
1809 | sigill: | ||
1810 | uprobe_warn(current, "handle uretprobe, sending SIGILL."); | ||
1811 | force_sig_info(SIGILL, SEND_SIG_FORCED, current); | ||
1807 | 1812 | ||
1808 | return true; | ||
1809 | } | 1813 | } |
1810 | 1814 | ||
1811 | bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs) | 1815 | bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs) |
@@ -1824,13 +1828,8 @@ static void handle_swbp(struct pt_regs *regs) | |||
1824 | int uninitialized_var(is_swbp); | 1828 | int uninitialized_var(is_swbp); |
1825 | 1829 | ||
1826 | bp_vaddr = uprobe_get_swbp_addr(regs); | 1830 | bp_vaddr = uprobe_get_swbp_addr(regs); |
1827 | if (bp_vaddr == get_trampoline_vaddr()) { | 1831 | if (bp_vaddr == get_trampoline_vaddr()) |
1828 | if (handle_trampoline(regs)) | 1832 | return handle_trampoline(regs); |
1829 | return; | ||
1830 | |||
1831 | pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n", | ||
1832 | current->pid, current->tgid); | ||
1833 | } | ||
1834 | 1833 | ||
1835 | uprobe = find_active_uprobe(bp_vaddr, &is_swbp); | 1834 | uprobe = find_active_uprobe(bp_vaddr, &is_swbp); |
1836 | if (!uprobe) { | 1835 | if (!uprobe) { |