aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kprobes.c
diff options
context:
space:
mode:
authorJason Baron <jbaron@redhat.com>2010-10-01 17:23:48 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-10-28 09:17:40 -0400
commit91bad2f8d3057482b9afb599f14421b007136960 (patch)
treeea5e09e74107593dcfc192c65c1395ed22674df4 /kernel/kprobes.c
parentb842f8faf6c7dc2005c6a70631c1a91bac02f180 (diff)
jump label: Fix deadlock b/w jump_label_mutex vs. text_mutex
register_kprobe() downs the 'text_mutex' and then calls jump_label_text_reserved(), which downs the 'jump_label_mutex'. However, the jump label code takes those mutexes in the reverse order. Fix by requiring the caller of jump_label_text_reserved() to do the jump label locking via the newly added: jump_label_lock(), jump_label_unlock(). Currently, kprobes is the only user of jump_label_text_reserved(). Reported-by: Ingo Molnar <mingo@elte.hu> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Jason Baron <jbaron@redhat.com> LKML-Reference: <759032c48d5e30c27f0bba003d09bffa8e9f28bb.1285965957.git.jbaron@redhat.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/kprobes.c')
-rw-r--r--kernel/kprobes.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 99865c33a60d..9437e14f36bd 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1146,13 +1146,16 @@ int __kprobes register_kprobe(struct kprobe *p)
1146 return ret; 1146 return ret;
1147 1147
1148 preempt_disable(); 1148 preempt_disable();
1149 jump_label_lock();
1149 if (!kernel_text_address((unsigned long) p->addr) || 1150 if (!kernel_text_address((unsigned long) p->addr) ||
1150 in_kprobes_functions((unsigned long) p->addr) || 1151 in_kprobes_functions((unsigned long) p->addr) ||
1151 ftrace_text_reserved(p->addr, p->addr) || 1152 ftrace_text_reserved(p->addr, p->addr) ||
1152 jump_label_text_reserved(p->addr, p->addr)) { 1153 jump_label_text_reserved(p->addr, p->addr)) {
1153 preempt_enable(); 1154 preempt_enable();
1155 jump_label_unlock();
1154 return -EINVAL; 1156 return -EINVAL;
1155 } 1157 }
1158 jump_label_unlock();
1156 1159
1157 /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */ 1160 /* User can pass only KPROBE_FLAG_DISABLED to register_kprobe */
1158 p->flags &= KPROBE_FLAG_DISABLED; 1161 p->flags &= KPROBE_FLAG_DISABLED;
@@ -1187,6 +1190,8 @@ int __kprobes register_kprobe(struct kprobe *p)
1187 INIT_LIST_HEAD(&p->list); 1190 INIT_LIST_HEAD(&p->list);
1188 mutex_lock(&kprobe_mutex); 1191 mutex_lock(&kprobe_mutex);
1189 1192
1193 jump_label_lock(); /* needed to call jump_label_text_reserved() */
1194
1190 get_online_cpus(); /* For avoiding text_mutex deadlock. */ 1195 get_online_cpus(); /* For avoiding text_mutex deadlock. */
1191 mutex_lock(&text_mutex); 1196 mutex_lock(&text_mutex);
1192 1197
@@ -1214,6 +1219,7 @@ int __kprobes register_kprobe(struct kprobe *p)
1214out: 1219out:
1215 mutex_unlock(&text_mutex); 1220 mutex_unlock(&text_mutex);
1216 put_online_cpus(); 1221 put_online_cpus();
1222 jump_label_unlock();
1217 mutex_unlock(&kprobe_mutex); 1223 mutex_unlock(&kprobe_mutex);
1218 1224
1219 if (probed_mod) 1225 if (probed_mod)