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 | |
| 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>
| -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 | } |
