Message ID | 20221114022946.66255-1-yangjihong1@huawei.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1931430wru; Sun, 13 Nov 2022 18:54:52 -0800 (PST) X-Google-Smtp-Source: AA0mqf7iSBfDlfi0eXWlMz6odI+Rvu9vIGOc8NzDcctFVsiLU7T84Df+h+cDVhCHcbZGBIzfJTkU X-Received: by 2002:aa7:c384:0:b0:461:5f19:61da with SMTP id k4-20020aa7c384000000b004615f1961damr9793964edq.34.1668394492336; Sun, 13 Nov 2022 18:54:52 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668394492; cv=none; d=google.com; s=arc-20160816; b=phn8p7fK9EbJiH4W8nX3d98zjClQfJTnmEetAQyXsNVYmwzcVnVmL5wUD9e9qAjNdp DDqbZ97mgPljOty5nV5a4O+AvfI/w/y31eyHvRryDB1Y0+dwF7BJs8nv/eWMF62nLPSq ZjApy0ciaZy386yHOumVFH+R+4EIWjOM/lcJu2B/RJjXdAa91aE90yiG9xI1ERtBFd0Z vyOD5g8yDnK1t1Skb9Pze4hxonfglFFRQ3JEsFFNMR1KQMeTu4jW01P7TkE64Gudo/Ee VWNEdgJGVFdNJ3oy5BqhShhHAJaOX+S+r3ZWDFLoydQL1yQGadshvlv8HBAwdM/hHdtF d7bA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=M6NhVjbalKg1NhuI+EvCeLZxeM6a0eXsfKIjzZyB1vE=; b=Y5615aMpw+ydtytmWHSHXE5CymFCgqwLLKZyWqyHm7EB3QBAOzFkeJgdXx+cUlinfx Yg08grYHwMo2vE2IGIzZkIo6kMqGFiRjDsfRR+4Q2onHwsHpUoja4Jl290V/C5K0qbth TW5OTnSffyLMpr8m2aehn5V1oRfqUSPz1BSUdzvKeRNUbTHyJw4fBtJQYsevoSX9A9w3 unabbxeDvbhI4MWVN4SnOdZNfL8CmmNO7tpRN0jJe+AH51zxy2gNqWVZAy1LzIWXARm8 WOa3P215E6px73aclTUXE52970fcuaKcK8sBPi2izxjslmbhEE4XzYg7qYeFQ7bwCX3/ rhcA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id u13-20020aa7d88d000000b00460ce6c3a1asi6552966edq.454.2022.11.13.18.54.28; Sun, 13 Nov 2022 18:54:52 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235551AbiKNCdB (ORCPT <rfc822;winker.wchi@gmail.com> + 99 others); Sun, 13 Nov 2022 21:33:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229720AbiKNCdA (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Sun, 13 Nov 2022 21:33:00 -0500 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 53ACBDE94 for <linux-kernel@vger.kernel.org>; Sun, 13 Nov 2022 18:32:56 -0800 (PST) Received: from dggemv703-chm.china.huawei.com (unknown [172.30.72.55]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4N9YHp35T5zRp2l; Mon, 14 Nov 2022 10:32:38 +0800 (CST) Received: from kwepemm600003.china.huawei.com (7.193.23.202) by dggemv703-chm.china.huawei.com (10.3.19.46) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.31; Mon, 14 Nov 2022 10:32:54 +0800 Received: from ubuntu1804.huawei.com (10.67.174.61) by kwepemm600003.china.huawei.com (7.193.23.202) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.31; Mon, 14 Nov 2022 10:32:54 +0800 From: Yang Jihong <yangjihong1@huawei.com> To: <rostedt@goodmis.org>, <mhiramat@kernel.org>, <linux-kernel@vger.kernel.org> CC: <yangjihong1@huawei.com> Subject: [PATCH] tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line Date: Mon, 14 Nov 2022 10:29:46 +0800 Message-ID: <20221114022946.66255-1-yangjihong1@huawei.com> X-Mailer: git-send-email 2.30.GIT MIME-Version: 1.0 Content-Transfer-Encoding: 7BIT Content-Type: text/plain; charset=US-ASCII X-Originating-IP: [10.67.174.61] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To kwepemm600003.china.huawei.com (7.193.23.202) X-CFilter-Loop: Reflected X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749438423005651943?= X-GMAIL-MSGID: =?utf-8?q?1749438423005651943?= |
Series |
tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line
|
|
Commit Message
Yang Jihong
Nov. 14, 2022, 2:29 a.m. UTC
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>
---
kernel/trace/trace.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
Comments
On Mon, 14 Nov 2022 10:29:46 +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> > --- > kernel/trace/trace.c | 13 +++++++++++++ > 1 file changed, 13 insertions(+) > > diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c > index 47a44b055a1d..2a8d5c68c29b 100644 > --- a/kernel/trace/trace.c > +++ b/kernel/trace/trace.c > @@ -6788,6 +6788,19 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, > if (ret == TRACE_TYPE_PARTIAL_LINE) { > /* don't print partial lines */ > iter->seq.seq.len = save_len; > + > + /* > + * If one trace_line of the tracer overflows seq_file > + * buffer, trace_seq_to_user returns -EBUSY because > + * nothing in the sequence (iter->seq.seq.len = \ > + * iter->seq.seq.readpos = 0). > + * In this case, we need to consume, otherwise, > + * "while" will peek this event next time, resulting > + * in an infinite loop. > + */ > + if (trace_seq_has_overflowed(&iter->seq)) > + trace_consume(iter); Instead of consuming it, I think the right solution is to print the partial line. Something like: if (trace_seq_has_overflowed(&iter->seq)) { char dots[] = "..."; iter->seq.seq.len -= sizeof(dots) + 1; iter->seq.seq.full = 0; trace_seq_puts(&iter->seq, dots); trace_consume(iter); break; } iter->seq.seq.len = save_len; break; That way we can see the broken trace event and not just silently drop it. -- Steve > + > break; > } > if (ret != TRACE_TYPE_NO_CONSUME)
Hello, On 2022/11/18 5:40, Steven Rostedt wrote: > On Mon, 14 Nov 2022 10:29:46 +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> >> --- >> kernel/trace/trace.c | 13 +++++++++++++ >> 1 file changed, 13 insertions(+) >> >> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c >> index 47a44b055a1d..2a8d5c68c29b 100644 >> --- a/kernel/trace/trace.c >> +++ b/kernel/trace/trace.c >> @@ -6788,6 +6788,19 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, >> if (ret == TRACE_TYPE_PARTIAL_LINE) { >> /* don't print partial lines */ >> iter->seq.seq.len = save_len; >> + >> + /* >> + * If one trace_line of the tracer overflows seq_file >> + * buffer, trace_seq_to_user returns -EBUSY because >> + * nothing in the sequence (iter->seq.seq.len = \ >> + * iter->seq.seq.readpos = 0). >> + * In this case, we need to consume, otherwise, >> + * "while" will peek this event next time, resulting >> + * in an infinite loop. >> + */ >> + if (trace_seq_has_overflowed(&iter->seq)) >> + trace_consume(iter); > > Instead of consuming it, I think the right solution is to print the partial > line. Something like: > > if (trace_seq_has_overflowed(&iter->seq)) { > char dots[] = "..."; > > iter->seq.seq.len -= sizeof(dots) + 1; > iter->seq.seq.full = 0; > trace_seq_puts(&iter->seq, dots); > trace_consume(iter); > break; > } > > iter->seq.seq.len = save_len; > break; > > That way we can see the broken trace event and not just silently drop it. > Ok, will change in next version.(Because iter->seq.seq.len may be smaller than strlen(dots), direct subtraction here may not be appropriate.) Thanks, Yang
On Fri, 18 Nov 2022 18:21:12 +0800 Yang Jihong <yangjihong1@huawei.com> wrote: > > That way we can see the broken trace event and not just silently drop it. > > > Ok, will change in next version.(Because iter->seq.seq.len may be > smaller than strlen(dots), direct subtraction here may not be appropriate.) We should only need to do this if the len is maxed out. Hmm, len is only updated if it did actually copy it. Perhaps we could just add: trace_seq_puts(&iter->seq, "[LINE TOO BIG]\n"); And perhaps that will work? Anyway, what is triggering this? -- Steve
Hello, On 2022/11/21 3:49, Steven Rostedt wrote: > On Fri, 18 Nov 2022 18:21:12 +0800 > Yang Jihong <yangjihong1@huawei.com> wrote: > >>> That way we can see the broken trace event and not just silently drop it. >>> >> Ok, will change in next version.(Because iter->seq.seq.len may be >> smaller than strlen(dots), direct subtraction here may not be appropriate.) > > We should only need to do this if the len is maxed out. > > Hmm, len is only updated if it did actually copy it. > > Perhaps we could just add: > > trace_seq_puts(&iter->seq, "[LINE TOO BIG]\n"); > > And perhaps that will work? > Yes, as you mentioned in the v2 patch: "The case I believe you are fixing, is the case were one print_trace_line() actually fills the entire trace_seq in one shot." The problem I'm having is exactly that. Just add "trace_seq_puts(&iter->seq, "[LINE TOO BIG]\n"); " can solve this problem. But I thought it might happen. (Not yet. Is it possible to support new tracers in the future?) print_one_line { char buf[4090]; // there's some data in the buf. trace_seq_puts(s, buf); // trace_seq buffer write successfully trace_seq_puts(s, "test, test, test\n"); // trace_seq buffer overflow } If we want to print out the boken event (buf[4090]), we may need to reserve space as we did before. If we don't consider this situation, we can just add "trace_seq_puts(&iter->seq, "[LINE TOO BIG]\n");", it's fine. > Anyway, what is triggering this? In my environment, this problem may be triggered in the following ways: # echo 1 > /sys/kernel/debug/tracing/options/blk_classic # echo 1 > /sys/kernel/debug/tracing/options/blk_cgroup # echo 1 > /sys/kernel/debug/tracing/events/enable # echo blk > /sys/kernel/debug/tracing/current_tracer # cat /sys/kernel/debug/tracing/trace_pipe > /dev/null trace_pipe enter the blk_log_dump_pdu function through the following call stack: tracing_read_pipe -> print_trace_line -> iter->trace->print_line (current_trace == blk) -> blk_tracer_print_line -> print_one_line -> blk_log_generic -> blk_log_dump_pdu static void blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent, bool has_cg) { ... for (i = 0; i < pdu_len; i++) { trace_seq_printf(s, "%s%02x", i == 0 ? "" : " ", pdu_buf[i]); /* * stop when the rest is just zeros and indicate so * with a ".." appended */ if (i == end && end != pdu_len - 1) { trace_seq_puts(s, " ..) "); return; } } ... } After the blk_classic option is enabled, blktrace writes all events in the ring buffer to the trace_seq buffer through blk_log_dump_pdu. If the value of pdu_len is too large, the buffer overflow may occur. (This problem may be caused by improper processing of blktrace.) Thanks, Yang
Hello, On 2022/11/21 3:49, Steven Rostedt wrote: > On Fri, 18 Nov 2022 18:21:12 +0800 > Yang Jihong <yangjihong1@huawei.com> wrote: > >>> That way we can see the broken trace event and not just silently drop it. >>> >> Ok, will change in next version.(Because iter->seq.seq.len may be >> smaller than strlen(dots), direct subtraction here may not be appropriate.) > > We should only need to do this if the len is maxed out. > > Hmm, len is only updated if it did actually copy it. > > Perhaps we could just add: > > trace_seq_puts(&iter->seq, "[LINE TOO BIG]\n"); > The v3 patch has been sent according to this solution. Thanks, Yang
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 47a44b055a1d..2a8d5c68c29b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6788,6 +6788,19 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, if (ret == TRACE_TYPE_PARTIAL_LINE) { /* don't print partial lines */ iter->seq.seq.len = save_len; + + /* + * If one trace_line of the tracer overflows seq_file + * buffer, trace_seq_to_user returns -EBUSY because + * nothing in the sequence (iter->seq.seq.len = \ + * iter->seq.seq.readpos = 0). + * In this case, we need to consume, otherwise, + * "while" will peek this event next time, resulting + * in an infinite loop. + */ + if (trace_seq_has_overflowed(&iter->seq)) + trace_consume(iter); + break; } if (ret != TRACE_TYPE_NO_CONSUME)