Specifically, get rid of the uprobe->consumers re-load, which isn't
sound under RCU.

Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org>
---
 kernel/events/uprobes.c |   17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -2101,6 +2101,7 @@ static void handler_chain(struct uprobe
        struct uprobe_consumer *uc;
        int remove = UPROBE_HANDLER_REMOVE;
        bool need_prep = false; /* prepare return uprobe, when needed */
+       bool had_handler = false;
 
        down_read(&uprobe->register_rwsem);
        for (uc = uprobe->consumers; uc; uc = uc->next) {
@@ -2115,16 +2116,26 @@ static void handler_chain(struct uprobe
                if (uc->ret_handler)
                        need_prep = true;
 
+               /*
+                * A single handler that does not mask out REMOVE, means the
+                * probe stays.
+                */
+               had_handler = true;
                remove &= rc;
        }
 
+       /*
+        * If there were no handlers called, nobody asked for it to be removed
+        * but also nobody got to mask the value. Fix it up.
+        */
+       if (!had_handler)
+               remove = 0;
+
        if (need_prep && !remove)
                prepare_uretprobe(uprobe, regs); /* put bp at return */
 
-       if (remove && uprobe->consumers) {
-               WARN_ON(!uprobe_is_active(uprobe));
+       if (remove)
                unapply_uprobe(uprobe, current->mm);
-       }
        up_read(&uprobe->register_rwsem);
 }
 



Reply via email to