| From 6b88f44e161b9ee2a803e5b2b1fbcf4e20e8b980 Mon Sep 17 00:00:00 2001 |
| From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org> |
| Date: Thu, 25 Jun 2015 18:10:09 -0400 |
| Subject: tracing/filter: Do not allow infix to exceed end of string |
| |
| From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org> |
| |
| commit 6b88f44e161b9ee2a803e5b2b1fbcf4e20e8b980 upstream. |
| |
| While debugging a WARN_ON() for filtering, I found that it is possible |
| for the filter string to be referenced after its end. With the filter: |
| |
| # echo '>' > /sys/kernel/debug/events/ext4/ext4_truncate_exit/filter |
| |
| The filter_parse() function can call infix_get_op() which calls |
| infix_advance() that updates the infix filter pointers for the cnt |
| and tail without checking if the filter is already at the end, which |
| will put the cnt to zero and the tail beyond the end. The loop then calls |
| infix_next() that has |
| |
| ps->infix.cnt--; |
| return ps->infix.string[ps->infix.tail++]; |
| |
| The cnt will now be below zero, and the tail that is returned is |
| already passed the end of the filter string. So far the allocation |
| of the filter string usually has some buffer that is zeroed out, but |
| if the filter string is of the exact size of the allocated buffer |
| there's no guarantee that the charater after the nul terminating |
| character will be zero. |
| |
| Luckily, only root can write to the filter. |
| |
| Signed-off-by: Steven Rostedt <rostedt@goodmis.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/trace/trace_events_filter.c | 6 ++++++ |
| 1 file changed, 6 insertions(+) |
| |
| --- a/kernel/trace/trace_events_filter.c |
| +++ b/kernel/trace/trace_events_filter.c |
| @@ -1015,6 +1015,9 @@ static void parse_init(struct filter_par |
| |
| static char infix_next(struct filter_parse_state *ps) |
| { |
| + if (!ps->infix.cnt) |
| + return 0; |
| + |
| ps->infix.cnt--; |
| |
| return ps->infix.string[ps->infix.tail++]; |
| @@ -1030,6 +1033,9 @@ static char infix_peek(struct filter_par |
| |
| static void infix_advance(struct filter_parse_state *ps) |
| { |
| + if (!ps->infix.cnt) |
| + return; |
| + |
| ps->infix.cnt--; |
| ps->infix.tail++; |
| } |