Context tracking recursion can happen when an exception triggers in the
middle of a call to a context tracking probe.

This special case can be caused by vmalloc faults. If an access to a
memory area allocated by vmalloc happens in the middle of
context_tracking_enter(), we may run into an endless fault loop because
the exception in turn calls context_tracking_enter() which faults on
the same vmalloc'ed memory, triggering an exception again, etc...

Some rare crashes have been reported so lets protect against this with
a recursion counter.

Reported-by: Dave Jones <da...@redhat.com>
Reviewed-by: Rik van Riel <r...@redhat.com>
Acked-by: Peter Zijlstra (Intel) <pet...@infradead.org>
Signed-off-by: Frederic Weisbecker <fweis...@gmail.com>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Rik van Riel <r...@redhat.com>
Cc: Paul E. McKenney <paul...@linux.vnet.ibm.com>
Cc: Ingo Molnar <mi...@kernel.org>
Cc: Dave Jones <da...@redhat.com>
Cc: Oleg Nesterov <o...@redhat.com>
---
 include/linux/context_tracking_state.h |  1 +
 kernel/context_tracking.c              | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/include/linux/context_tracking_state.h 
b/include/linux/context_tracking_state.h
index 6b7b96a..678ecdf 100644
--- a/include/linux/context_tracking_state.h
+++ b/include/linux/context_tracking_state.h
@@ -12,6 +12,7 @@ struct context_tracking {
         * may be further optimized using static keys.
         */
        bool active;
+       int recursion;
        enum ctx_state {
                CONTEXT_KERNEL = 0,
                CONTEXT_USER,
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 72d59a1..b9e0b4f 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -38,6 +38,25 @@ void context_tracking_cpu_set(int cpu)
        }
 }
 
+static bool context_tracking_recursion_enter(void)
+{
+       int recursion;
+
+       recursion = __this_cpu_inc_return(context_tracking.recursion);
+       if (recursion == 1)
+               return true;
+
+       WARN_ONCE((recursion < 1), "Invalid context tracking recursion value 
%d\n", recursion);
+       __this_cpu_dec(context_tracking.recursion);
+
+       return false;
+}
+
+static void context_tracking_recursion_exit(void)
+{
+       __this_cpu_dec(context_tracking.recursion);
+}
+
 /**
  * context_tracking_enter - Inform the context tracking that the CPU is going
  *                          enter user or guest space mode.
@@ -75,6 +94,11 @@ void context_tracking_enter(enum ctx_state state)
        WARN_ON_ONCE(!current->mm);
 
        local_irq_save(flags);
+       if (!context_tracking_recursion_enter()) {
+               local_irq_restore(flags);
+               return;
+       }
+
        if ( __this_cpu_read(context_tracking.state) != state) {
                if (__this_cpu_read(context_tracking.active)) {
                        /*
@@ -105,6 +129,7 @@ void context_tracking_enter(enum ctx_state state)
                 */
                __this_cpu_write(context_tracking.state, state);
        }
+       context_tracking_recursion_exit();
        local_irq_restore(flags);
 }
 NOKPROBE_SYMBOL(context_tracking_enter);
@@ -139,6 +164,10 @@ void context_tracking_exit(enum ctx_state state)
                return;
 
        local_irq_save(flags);
+       if (!context_tracking_recursion_enter()) {
+               local_irq_restore(flags);
+               return;
+       }
        if (__this_cpu_read(context_tracking.state) == state) {
                if (__this_cpu_read(context_tracking.active)) {
                        /*
@@ -153,6 +182,7 @@ void context_tracking_exit(enum ctx_state state)
                }
                __this_cpu_write(context_tracking.state, CONTEXT_KERNEL);
        }
+       context_tracking_recursion_exit();
        local_irq_restore(flags);
 }
 NOKPROBE_SYMBOL(context_tracking_exit);
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to