aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2015-05-06 12:04:23 -0400
committerIngo Molnar <mingo@kernel.org>2015-05-07 06:02:50 -0400
commitaed5ed47724f6a7453fa62e3c90f3cee93edbfe3 (patch)
tree216d3c4a8d7bfa2204052e89790f352ad0dcd1c1
parent0e1dc4274828f64fcb56fc7b950acdc5ff7a395f (diff)
context_tracking: Protect against recursion
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 <davej@redhat.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Reviewed-by: Rik van Riel <riel@redhat.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Chris Metcalf <cmetcalf@ezchip.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Mike Galbraith <umgwanakikbuti@gmail.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1430928266-24888-2-git-send-email-fweisbec@gmail.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/context_tracking_state.h1
-rw-r--r--kernel/context_tracking.c29
2 files changed, 30 insertions, 0 deletions
diff --git a/include/linux/context_tracking_state.h b/include/linux/context_tracking_state.h
index 6b7b96a32b75..678ecdf90cf6 100644
--- a/include/linux/context_tracking_state.h
+++ b/include/linux/context_tracking_state.h
@@ -12,6 +12,7 @@ struct context_tracking {
12 * may be further optimized using static keys. 12 * may be further optimized using static keys.
13 */ 13 */
14 bool active; 14 bool active;
15 int recursion;
15 enum ctx_state { 16 enum ctx_state {
16 CONTEXT_KERNEL = 0, 17 CONTEXT_KERNEL = 0,
17 CONTEXT_USER, 18 CONTEXT_USER,
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 72d59a1a6eb6..5b11a10e196a 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -38,6 +38,25 @@ void context_tracking_cpu_set(int cpu)
38 } 38 }
39} 39}
40 40
41static bool context_tracking_recursion_enter(void)
42{
43 int recursion;
44
45 recursion = __this_cpu_inc_return(context_tracking.recursion);
46 if (recursion == 1)
47 return true;
48
49 WARN_ONCE((recursion < 1), "Invalid context tracking recursion value %d\n", recursion);
50 __this_cpu_dec(context_tracking.recursion);
51
52 return false;
53}
54
55static void context_tracking_recursion_exit(void)
56{
57 __this_cpu_dec(context_tracking.recursion);
58}
59
41/** 60/**
42 * context_tracking_enter - Inform the context tracking that the CPU is going 61 * context_tracking_enter - Inform the context tracking that the CPU is going
43 * enter user or guest space mode. 62 * enter user or guest space mode.
@@ -75,6 +94,9 @@ void context_tracking_enter(enum ctx_state state)
75 WARN_ON_ONCE(!current->mm); 94 WARN_ON_ONCE(!current->mm);
76 95
77 local_irq_save(flags); 96 local_irq_save(flags);
97 if (!context_tracking_recursion_enter())
98 goto out_irq_restore;
99
78 if ( __this_cpu_read(context_tracking.state) != state) { 100 if ( __this_cpu_read(context_tracking.state) != state) {
79 if (__this_cpu_read(context_tracking.active)) { 101 if (__this_cpu_read(context_tracking.active)) {
80 /* 102 /*
@@ -105,6 +127,8 @@ void context_tracking_enter(enum ctx_state state)
105 */ 127 */
106 __this_cpu_write(context_tracking.state, state); 128 __this_cpu_write(context_tracking.state, state);
107 } 129 }
130 context_tracking_recursion_exit();
131out_irq_restore:
108 local_irq_restore(flags); 132 local_irq_restore(flags);
109} 133}
110NOKPROBE_SYMBOL(context_tracking_enter); 134NOKPROBE_SYMBOL(context_tracking_enter);
@@ -139,6 +163,9 @@ void context_tracking_exit(enum ctx_state state)
139 return; 163 return;
140 164
141 local_irq_save(flags); 165 local_irq_save(flags);
166 if (!context_tracking_recursion_enter())
167 goto out_irq_restore;
168
142 if (__this_cpu_read(context_tracking.state) == state) { 169 if (__this_cpu_read(context_tracking.state) == state) {
143 if (__this_cpu_read(context_tracking.active)) { 170 if (__this_cpu_read(context_tracking.active)) {
144 /* 171 /*
@@ -153,6 +180,8 @@ void context_tracking_exit(enum ctx_state state)
153 } 180 }
154 __this_cpu_write(context_tracking.state, CONTEXT_KERNEL); 181 __this_cpu_write(context_tracking.state, CONTEXT_KERNEL);
155 } 182 }
183 context_tracking_recursion_exit();
184out_irq_restore:
156 local_irq_restore(flags); 185 local_irq_restore(flags);
157} 186}
158NOKPROBE_SYMBOL(context_tracking_exit); 187NOKPROBE_SYMBOL(context_tracking_exit);