tracing: Enforce passing in filter=NULL to create_filter()

There's some inconsistency with what to set the output parameter filterp
when passing to create_filter(..., struct event_filter **filterp).

Whatever filterp points to, should be NULL when calling this function. The
create_filter() calls create_filter_start() with a pointer to a local
"filter" variable that is set to NULL. The create_filter_start() has a
WARN_ON() if the passed in pointer isn't pointing to a value set to NULL.

Ideally, create_filter() should pass the filterp variable it received to
create_filter_start() and not hide it as with a local variable, this allowed
create_filter() to fail, and not update the passed in filter, and the caller
of create_filter() then tried to free filter, which was never initialized to
anything, causing memory corruption.

Link: http://lkml.kernel.org/r/00000000000032a0c30569916870@google.com

Fixes: 80765597 ("tracing: Rewrite filter logic to be simpler and faster")
Reported-by: syzbot+dadcc936587643d7f568@syzkaller.appspotmail.com
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent a64b2c01
...@@ -1704,18 +1704,16 @@ static int create_filter(struct trace_event_call *call, ...@@ -1704,18 +1704,16 @@ static int create_filter(struct trace_event_call *call,
struct event_filter **filterp) struct event_filter **filterp)
{ {
struct filter_parse_error *pe = NULL; struct filter_parse_error *pe = NULL;
struct event_filter *filter = NULL;
int err; int err;
err = create_filter_start(filter_string, set_str, &pe, &filter); err = create_filter_start(filter_string, set_str, &pe, filterp);
if (err) if (err)
return err; return err;
err = process_preds(call, filter_string, filter, pe); err = process_preds(call, filter_string, *filterp, pe);
if (err && set_str) if (err && set_str)
append_filter_err(pe, filter); append_filter_err(pe, *filterp);
*filterp = filter;
return err; return err;
} }
...@@ -1739,24 +1737,22 @@ static int create_system_filter(struct trace_subsystem_dir *dir, ...@@ -1739,24 +1737,22 @@ static int create_system_filter(struct trace_subsystem_dir *dir,
struct trace_array *tr, struct trace_array *tr,
char *filter_str, struct event_filter **filterp) char *filter_str, struct event_filter **filterp)
{ {
struct event_filter *filter = NULL;
struct filter_parse_error *pe = NULL; struct filter_parse_error *pe = NULL;
int err; int err;
err = create_filter_start(filter_str, true, &pe, &filter); err = create_filter_start(filter_str, true, &pe, filterp);
if (!err) { if (!err) {
err = process_system_preds(dir, tr, pe, filter_str); err = process_system_preds(dir, tr, pe, filter_str);
if (!err) { if (!err) {
/* System filters just show a default message */ /* System filters just show a default message */
kfree(filter->filter_string); kfree((*filterp)->filter_string);
filter->filter_string = NULL; (*filterp)->filter_string = NULL;
} else { } else {
append_filter_err(pe, filter); append_filter_err(pe, *filterp);
} }
} }
create_filter_finish(pe); create_filter_finish(pe);
*filterp = filter;
return err; return err;
} }
...@@ -1764,7 +1760,7 @@ static int create_system_filter(struct trace_subsystem_dir *dir, ...@@ -1764,7 +1760,7 @@ static int create_system_filter(struct trace_subsystem_dir *dir,
int apply_event_filter(struct trace_event_file *file, char *filter_string) int apply_event_filter(struct trace_event_file *file, char *filter_string)
{ {
struct trace_event_call *call = file->event_call; struct trace_event_call *call = file->event_call;
struct event_filter *filter; struct event_filter *filter = NULL;
int err; int err;
if (!strcmp(strstrip(filter_string), "0")) { if (!strcmp(strstrip(filter_string), "0")) {
...@@ -1817,7 +1813,7 @@ int apply_subsystem_event_filter(struct trace_subsystem_dir *dir, ...@@ -1817,7 +1813,7 @@ int apply_subsystem_event_filter(struct trace_subsystem_dir *dir,
{ {
struct event_subsystem *system = dir->subsystem; struct event_subsystem *system = dir->subsystem;
struct trace_array *tr = dir->tr; struct trace_array *tr = dir->tr;
struct event_filter *filter; struct event_filter *filter = NULL;
int err = 0; int err = 0;
mutex_lock(&event_mutex); mutex_lock(&event_mutex);
...@@ -2024,7 +2020,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, ...@@ -2024,7 +2020,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
char *filter_str) char *filter_str)
{ {
int err; int err;
struct event_filter *filter; struct event_filter *filter = NULL;
struct trace_event_call *call; struct trace_event_call *call;
mutex_lock(&event_mutex); mutex_lock(&event_mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment