uprobes: Fix handle_swbp() vs. unregister() + register() race once more
authorAndrea Parri <[email protected]>
Thu, 22 Nov 2018 16:10:31 +0000 (17:10 +0100)
committerIngo Molnar <[email protected]>
Fri, 23 Nov 2018 07:31:19 +0000 (08:31 +0100)
Commit:

  142b18ddc8143 ("uprobes: Fix handle_swbp() vs unregister() + register() race")

added the UPROBE_COPY_INSN flag, and corresponding smp_wmb() and smp_rmb()
memory barriers, to ensure that handle_swbp() uses fully-initialized
uprobes only.

However, the smp_rmb() is mis-placed: this barrier should be placed
after handle_swbp() has tested for the flag, thus guaranteeing that
(program-order) subsequent loads from the uprobe can see the initial
stores performed by prepare_uprobe().

Move the smp_rmb() accordingly.  Also amend the comments associated
to the two memory barriers to indicate their actual locations.

Signed-off-by: Andrea Parri <[email protected]>
Acked-by: Oleg Nesterov <[email protected]>
Cc: Alexander Shishkin <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Vince Weaver <[email protected]>
Cc: [email protected]
Fixes: 142b18ddc8143 ("uprobes: Fix handle_swbp() vs unregister() + register() race")
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
kernel/events/uprobes.c

index 96d4bee83489b113a1f37452aeffb8e13461b230..322e97bbb4370a8ce4da1af39187dbc775fa83d4 100644 (file)
@@ -829,7 +829,7 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
        BUG_ON((uprobe->offset & ~PAGE_MASK) +
                        UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
 
-       smp_wmb(); /* pairs with rmb() in find_active_uprobe() */
+       smp_wmb(); /* pairs with the smp_rmb() in handle_swbp() */
        set_bit(UPROBE_COPY_INSN, &uprobe->flags);
 
  out:
@@ -2178,10 +2178,18 @@ static void handle_swbp(struct pt_regs *regs)
         * 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;
 
+       /*
+        * Pairs with the smp_wmb() in prepare_uprobe().
+        *
+        * Guarantees that if we see the UPROBE_COPY_INSN bit set, then
+        * we must also see the stores to &uprobe->arch performed by the
+        * prepare_uprobe() call.
+        */
+       smp_rmb();
+
        /* Tracing handlers use ->utask to communicate with fetch methods */
        if (!get_utask())
                goto out;