If we try to install a uprobe on a breakpoint instruction when the
binary has not yet been mmap'ed, we register the probe but delay
installing the breakpoint for when the binary is actually mmap'ed. On
mmap, uprobe_mmap() calls prepare_uprobe() which then refuses to install
the breakpoint. In this case however, when the breakpoint hits, we
incorrectly assume that the probe hit and end up looping.

This happens because find_active_uprobe() does not check if we
successfully installed the breakpoint or not. Fix this by checking if
UPROBE_COPY_INSN is set in uprobe->flags in find_active_uprobe().
Since handle_swbp() calls find_active_uprobe(), we can remove the
redundant check there.

Reported-by: Anton Blanchard <[email protected]>
Signed-off-by: Naveen N. Rao <[email protected]>
---
 kernel/events/uprobes.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 8da6570b4467..4c5dc6fb2abf 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1751,6 +1751,19 @@ static struct uprobe *find_active_uprobe(unsigned long 
bp_vaddr, int *is_swbp)
                        uprobe = find_uprobe(inode, offset);
                }
 
+               /* Ensure that the breakpoint was actually installed */
+               if (uprobe) {
+                       /*
+                        * TODO: move copy_insn/etc into _register and remove
+                        * this hack.  After we hit the bp, _unregister +
+                        * _register can install the new and not-yet-analyzed
+                        * uprobe at the same address, restart.
+                        */
+                       smp_rmb(); /* pairs with wmb() in prepare_uprobe() */
+                       if (unlikely(!test_bit(UPROBE_COPY_INSN, 
&uprobe->flags)))
+                               uprobe = NULL;
+               }
+
                if (!uprobe)
                        *is_swbp = is_trap_at_addr(mm, bp_vaddr);
        } else {
@@ -1911,15 +1924,6 @@ static void handle_swbp(struct pt_regs *regs)
        /* change it in advance for ->handler() and restart */
        instruction_pointer_set(regs, bp_vaddr);
 
-       /*
-        * TODO: move copy_insn/etc into _register and remove this hack.
-        * After we hit the bp, _unregister + _register can install the
-        * new and not-yet-analyzed uprobe at the same address, restart.
-        */
-       smp_rmb(); /* pairs with wmb() in install_breakpoint() */
-       if (unlikely(!test_bit(UPROBE_COPY_INSN, &uprobe->flags)))
-               goto out;
-
        /* Tracing handlers use ->utask to communicate with fetch methods */
        if (!get_utask())
                goto out;
-- 
2.14.1

Reply via email to