| From: "Steven Rostedt (VMware)" <rostedt@goodmis.org> |
| Date: Wed, 25 Jul 2018 16:02:06 -0400 |
| Subject: tracing: Fix possible double free in event_enable_trigger_func() |
| |
| commit 15cc78644d0075e76d59476a4467e7143860f660 upstream. |
| |
| There was a case that triggered a double free in event_trigger_callback() |
| due to the called reg() function freeing the trigger_data and then it |
| getting freed again by the error return by the caller. The solution there |
| was to up the trigger_data ref count. |
| |
| Code inspection found that event_enable_trigger_func() has the same issue, |
| but is not as easy to trigger (requires harder to trigger failures). It |
| needs to be solved slightly different as it needs more to clean up when the |
| reg() function fails. |
| |
| Link: http://lkml.kernel.org/r/20180725124008.7008e586@gandalf.local.home |
| |
| Fixes: 7862ad1846e99 ("tracing: Add 'enable_event' and 'disable_event' event trigger commands") |
| Reivewed-by: Masami Hiramatsu <mhiramat@kernel.org> |
| Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| kernel/trace/trace_events_trigger.c | 6 +++++- |
| 1 file changed, 5 insertions(+), 1 deletion(-) |
| |
| --- a/kernel/trace/trace_events_trigger.c |
| +++ b/kernel/trace/trace_events_trigger.c |
| @@ -1231,6 +1231,9 @@ event_enable_trigger_func(struct event_c |
| goto out; |
| } |
| |
| + /* Up the trigger_data count to make sure nothing frees it on failure */ |
| + event_trigger_init(trigger_ops, trigger_data); |
| + |
| if (trigger) { |
| number = strsep(&trigger, ":"); |
| |
| @@ -1281,6 +1284,7 @@ event_enable_trigger_func(struct event_c |
| goto out_disable; |
| /* Just return zero, not the number of enabled functions */ |
| ret = 0; |
| + event_trigger_free(trigger_ops, trigger_data); |
| out: |
| return ret; |
| |
| @@ -1291,7 +1295,7 @@ event_enable_trigger_func(struct event_c |
| out_free: |
| if (cmd_ops->set_filter) |
| cmd_ops->set_filter(NULL, trigger_data, NULL); |
| - kfree(trigger_data); |
| + event_trigger_free(trigger_ops, trigger_data); |
| kfree(enable_data); |
| goto out; |
| } |