diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2009-06-16 04:39:41 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2009-06-16 16:25:37 -0400 |
commit | 00e95830a4d6e49f764fdb19896a89199bc0aa3b (patch) | |
tree | 972a3872cb48474777da0f9e3121fcc6924e197d /kernel/trace | |
parent | 57be88878e7aa38750384704d811485a607bbda4 (diff) |
tracing/filters: fix race between filter setting and module unload
Module unload is protected by event_mutex, while setting filter is
protected by filter_mutex. This leads to the race:
echo 'bar == 0 || bar == 10' \ |
> sample/filter |
| insmod sample.ko
add_pred("bar == 0") |
-> n_preds == 1 |
add_pred("bar == 100") |
-> n_preds == 2 |
| rmmod sample.ko
| insmod sample.ko
add_pred("&&") |
-> n_preds == 1 (should be 3) |
Now event->filter->preds is corrupted. An then when filter_match_preds()
is called, the WARN_ON() in it will be triggered.
To avoid the race, we remove filter_mutex, and replace it with event_mutex.
[ Impact: prevent corruption of filters by module removing and loading ]
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
LKML-Reference: <4A375A4D.6000205@cn.fujitsu.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace_events_filter.c | 27 |
1 files changed, 10 insertions, 17 deletions
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index d9f01c1a042b..936c621bbf46 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -27,8 +27,6 @@ | |||
27 | #include "trace.h" | 27 | #include "trace.h" |
28 | #include "trace_output.h" | 28 | #include "trace_output.h" |
29 | 29 | ||
30 | static DEFINE_MUTEX(filter_mutex); | ||
31 | |||
32 | enum filter_op_ids | 30 | enum filter_op_ids |
33 | { | 31 | { |
34 | OP_OR, | 32 | OP_OR, |
@@ -294,12 +292,12 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) | |||
294 | { | 292 | { |
295 | struct event_filter *filter = call->filter; | 293 | struct event_filter *filter = call->filter; |
296 | 294 | ||
297 | mutex_lock(&filter_mutex); | 295 | mutex_lock(&event_mutex); |
298 | if (filter->filter_string) | 296 | if (filter->filter_string) |
299 | trace_seq_printf(s, "%s\n", filter->filter_string); | 297 | trace_seq_printf(s, "%s\n", filter->filter_string); |
300 | else | 298 | else |
301 | trace_seq_printf(s, "none\n"); | 299 | trace_seq_printf(s, "none\n"); |
302 | mutex_unlock(&filter_mutex); | 300 | mutex_unlock(&event_mutex); |
303 | } | 301 | } |
304 | 302 | ||
305 | void print_subsystem_event_filter(struct event_subsystem *system, | 303 | void print_subsystem_event_filter(struct event_subsystem *system, |
@@ -307,12 +305,12 @@ void print_subsystem_event_filter(struct event_subsystem *system, | |||
307 | { | 305 | { |
308 | struct event_filter *filter = system->filter; | 306 | struct event_filter *filter = system->filter; |
309 | 307 | ||
310 | mutex_lock(&filter_mutex); | 308 | mutex_lock(&event_mutex); |
311 | if (filter->filter_string) | 309 | if (filter->filter_string) |
312 | trace_seq_printf(s, "%s\n", filter->filter_string); | 310 | trace_seq_printf(s, "%s\n", filter->filter_string); |
313 | else | 311 | else |
314 | trace_seq_printf(s, "none\n"); | 312 | trace_seq_printf(s, "none\n"); |
315 | mutex_unlock(&filter_mutex); | 313 | mutex_unlock(&event_mutex); |
316 | } | 314 | } |
317 | 315 | ||
318 | static struct ftrace_event_field * | 316 | static struct ftrace_event_field * |
@@ -434,7 +432,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system) | |||
434 | filter->n_preds = 0; | 432 | filter->n_preds = 0; |
435 | } | 433 | } |
436 | 434 | ||
437 | mutex_lock(&event_mutex); | ||
438 | list_for_each_entry(call, &ftrace_events, list) { | 435 | list_for_each_entry(call, &ftrace_events, list) { |
439 | if (!call->define_fields) | 436 | if (!call->define_fields) |
440 | continue; | 437 | continue; |
@@ -444,7 +441,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system) | |||
444 | remove_filter_string(call->filter); | 441 | remove_filter_string(call->filter); |
445 | } | 442 | } |
446 | } | 443 | } |
447 | mutex_unlock(&event_mutex); | ||
448 | } | 444 | } |
449 | 445 | ||
450 | static int filter_add_pred_fn(struct filter_parse_state *ps, | 446 | static int filter_add_pred_fn(struct filter_parse_state *ps, |
@@ -631,7 +627,6 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps, | |||
631 | filter->preds[filter->n_preds] = pred; | 627 | filter->preds[filter->n_preds] = pred; |
632 | filter->n_preds++; | 628 | filter->n_preds++; |
633 | 629 | ||
634 | mutex_lock(&event_mutex); | ||
635 | list_for_each_entry(call, &ftrace_events, list) { | 630 | list_for_each_entry(call, &ftrace_events, list) { |
636 | 631 | ||
637 | if (!call->define_fields) | 632 | if (!call->define_fields) |
@@ -642,14 +637,12 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps, | |||
642 | 637 | ||
643 | err = filter_add_pred(ps, call, pred); | 638 | err = filter_add_pred(ps, call, pred); |
644 | if (err) { | 639 | if (err) { |
645 | mutex_unlock(&event_mutex); | ||
646 | filter_free_subsystem_preds(system); | 640 | filter_free_subsystem_preds(system); |
647 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); | 641 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); |
648 | goto out; | 642 | goto out; |
649 | } | 643 | } |
650 | replace_filter_string(call->filter, filter_string); | 644 | replace_filter_string(call->filter, filter_string); |
651 | } | 645 | } |
652 | mutex_unlock(&event_mutex); | ||
653 | out: | 646 | out: |
654 | return err; | 647 | return err; |
655 | } | 648 | } |
@@ -1076,12 +1069,12 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
1076 | 1069 | ||
1077 | struct filter_parse_state *ps; | 1070 | struct filter_parse_state *ps; |
1078 | 1071 | ||
1079 | mutex_lock(&filter_mutex); | 1072 | mutex_lock(&event_mutex); |
1080 | 1073 | ||
1081 | if (!strcmp(strstrip(filter_string), "0")) { | 1074 | if (!strcmp(strstrip(filter_string), "0")) { |
1082 | filter_disable_preds(call); | 1075 | filter_disable_preds(call); |
1083 | remove_filter_string(call->filter); | 1076 | remove_filter_string(call->filter); |
1084 | mutex_unlock(&filter_mutex); | 1077 | mutex_unlock(&event_mutex); |
1085 | return 0; | 1078 | return 0; |
1086 | } | 1079 | } |
1087 | 1080 | ||
@@ -1109,7 +1102,7 @@ out: | |||
1109 | postfix_clear(ps); | 1102 | postfix_clear(ps); |
1110 | kfree(ps); | 1103 | kfree(ps); |
1111 | out_unlock: | 1104 | out_unlock: |
1112 | mutex_unlock(&filter_mutex); | 1105 | mutex_unlock(&event_mutex); |
1113 | 1106 | ||
1114 | return err; | 1107 | return err; |
1115 | } | 1108 | } |
@@ -1121,12 +1114,12 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
1121 | 1114 | ||
1122 | struct filter_parse_state *ps; | 1115 | struct filter_parse_state *ps; |
1123 | 1116 | ||
1124 | mutex_lock(&filter_mutex); | 1117 | mutex_lock(&event_mutex); |
1125 | 1118 | ||
1126 | if (!strcmp(strstrip(filter_string), "0")) { | 1119 | if (!strcmp(strstrip(filter_string), "0")) { |
1127 | filter_free_subsystem_preds(system); | 1120 | filter_free_subsystem_preds(system); |
1128 | remove_filter_string(system->filter); | 1121 | remove_filter_string(system->filter); |
1129 | mutex_unlock(&filter_mutex); | 1122 | mutex_unlock(&event_mutex); |
1130 | return 0; | 1123 | return 0; |
1131 | } | 1124 | } |
1132 | 1125 | ||
@@ -1154,7 +1147,7 @@ out: | |||
1154 | postfix_clear(ps); | 1147 | postfix_clear(ps); |
1155 | kfree(ps); | 1148 | kfree(ps); |
1156 | out_unlock: | 1149 | out_unlock: |
1157 | mutex_unlock(&filter_mutex); | 1150 | mutex_unlock(&event_mutex); |
1158 | 1151 | ||
1159 | return err; | 1152 | return err; |
1160 | } | 1153 | } |