Messages in this thread | | | Date | Sun, 20 Nov 2022 14:38:52 -0500 | From | Steven Rostedt <> | Subject | Re: [PATCH v2] tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line |
| |
On Fri, 18 Nov 2022 18:25:21 +0800 Yang Jihong <yangjihong1@huawei.com> wrote:
> print_trace_line may overflow seq_file buffer. If the event is not > consumed, the while loop keeps peeking this event, causing a infinite loop. > > Signed-off-by: Yang Jihong <yangjihong1@huawei.com> > --- > > Changes since v1: > - Print partial line to show the broken trace event when overflowed print_trace_line > > kernel/trace/trace.c | 27 ++++++++++++++++++++++++++- > 1 file changed, 26 insertions(+), 1 deletion(-) > > diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c > index 47a44b055a1d..81c36dc80212 100644 > --- a/kernel/trace/trace.c > +++ b/kernel/trace/trace.c > @@ -6786,7 +6786,32 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, > > ret = print_trace_line(iter); > if (ret == TRACE_TYPE_PARTIAL_LINE) { > - /* don't print partial lines */ > + /* > + * If one trace_line of the tracer overflows seq_file > + * buffer, trace_seq_to_user returns -EBUSY. > + * In this case, we need to consume, otherwise, > + * while loop will peek this event next time, > + * resulting in an infinite loop. > + */ > + if (trace_seq_has_overflowed(&iter->seq)) {
We need to only do this if save_len is zero. Because the reason that it returns TRACE_TYPE_PARTIAL_LINE is usually because it overflowed.
This loops until the trace_seq is full, so it's OK to have it overflow. The case I believe you are fixing, is the case were one print_trace_line() actually fills the entire trace_seq in one shot. In which case, it will never print, and in that case, save_len will be zero.
-- Steve
> + /* > + * Print the partial line, > + * that way we can see the broken trace event. > + */ > + char dots[] = "...\n"; > + > + iter->seq.full = 0; > + if (seq_buf_buffer_left(&iter->seq.seq) < strlen(dots)) { > + iter->seq.seq.len = > + seq_buf_used(&iter->seq.seq) - strlen(dots); > + } > + trace_seq_puts(&iter->seq, dots); > + > + trace_consume(iter); > + break; > + } > + > + /* In other cases, don't print partial lines */ > iter->seq.seq.len = save_len; > break; > }
| |