diff options
| author | Jason Baron <jbaron@redhat.com> | 2010-10-01 17:23:48 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-10-28 09:17:40 -0400 |
| commit | 91bad2f8d3057482b9afb599f14421b007136960 (patch) | |
| tree | ea5e09e74107593dcfc192c65c1395ed22674df4 /kernel/kprobes.c | |
| parent | b842f8faf6c7dc2005c6a70631c1a91bac02f180 (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.c | 6 |
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) | |||
| 1214 | out: | 1219 | out: |
| 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) |
