summaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_events.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-05-07 03:54:09 +0200
committerSteven Rostedt <rostedt@goodmis.org>2009-05-07 05:11:41 +0200
commit9456f0fa6d3cb944d3b9fc31c9a244e0362c26ea (patch)
tree9e6e97199f63c786a79966a5938873a98591e10c /kernel/trace/trace_events.c
parenttracing: update sample with TRACE_INCLUDE_FILE (diff)
downloadlinux-9456f0fa6d3cb944d3b9fc31c9a244e0362c26ea.tar.xz
linux-9456f0fa6d3cb944d3b9fc31c9a244e0362c26ea.zip
tracing: reset ring buffer when removing modules with events
Li Zefan found that there's a race using the event ids of events and modules. When a module is loaded, an event id is incremented. We only have 16 bits for event ids (65536) and there is a possible (but highly unlikely) race that we could load and unload a module that registers events so many times that the event id counter overflows. When it overflows, it then restarts and goes looking for available ids. An id is available if it was added by a module and released. The race is if you have one module add an id, and then is removed. Another module loaded can use that same event id. But if the old module still had events in the ring buffer, the new module's call back would get bogus data. At best (and most likely) the output would just be garbage. But if the module for some reason used pointers (not recommended) then this could potentially crash. The safest thing to do is just reset the ring buffer if a module that registered events is removed. [ Impact: prevent unpredictable results of event id overflows ] Reported-by: Li Zefan <lizf@cn.fujitsu.com> LKML-Reference: <49FEAFD0.30106@cn.fujitsu.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r--kernel/trace/trace_events.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 8d579ff23610..6d2c842a0248 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -932,9 +932,11 @@ static void trace_module_remove_events(struct module *mod)
{
struct ftrace_module_file_ops *file_ops;
struct ftrace_event_call *call, *p;
+ bool found = false;
list_for_each_entry_safe(call, p, &ftrace_events, list) {
if (call->mod == mod) {
+ found = true;
if (call->enabled) {
call->enabled = 0;
call->unregfunc();
@@ -957,6 +959,13 @@ static void trace_module_remove_events(struct module *mod)
list_del(&file_ops->list);
kfree(file_ops);
}
+
+ /*
+ * It is safest to reset the ring buffer if the module being unloaded
+ * registered any events.
+ */
+ if (found)
+ tracing_reset_current_online_cpus();
}
static int trace_module_notify(struct notifier_block *self,