Message ID | 20230308070844.58180-1-chenzhongjin@huawei.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp184371wrd; Tue, 7 Mar 2023 23:17:42 -0800 (PST) X-Google-Smtp-Source: AK7set89esOjHDH/xC7JJU3BMq9WGWH6fq2pP80XPtMpjk3xUHArE6zx8wFaMx+lbjj+IHsgouEB X-Received: by 2002:a17:90b:3b45:b0:231:284:ea4d with SMTP id ot5-20020a17090b3b4500b002310284ea4dmr17208009pjb.22.1678259862512; Tue, 07 Mar 2023 23:17:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1678259862; cv=none; d=google.com; s=arc-20160816; b=JrJapiQno9aNu0lB13PFl9o8T1ehzcZ0XLE8AQJaOeCgnwI8xgIDWAeLXnDFdfOnZx OJu+seqm5+IQGERmO7VfS611TJ/onkxgC8wk3zlI6qFtbI+/scULENpti8t8IQoMxjlO bbn86ADuNFPoirYMiGnpO7M3hNsecoEWik1jDIkUw84LdrH9yWzQwrXeEtra70gLFBAC Ji9EDrpHQ3jRuzS/WRRqXZSPQA/d8BiiOymPqDGYxqFhO74ZCQ26gIHSYrpb5F1uf9Fp uTNX7o5JA0CZBWjwX3h0O+uEdoL+vY+upwptcvSxz8D50TNuIODXC98o3lbpD6BVVYo7 gVDw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:message-id:date:subject:cc:to:from; bh=Je6lH+9UjVMbJxAxkMvdJUHBVkhfK04dgHyeJ6Bv7KQ=; b=IbLKQVEUFbou1xkeK7BSGzfdsLby6IioxIDkEOlhQr2Qswnx5Xn1lcE86UPDn1FUDc 5yIqcrJLgRpXv38H9giwkTJeI587zIWHofNuSCf3i2uIXajPe7ThreVMGLp8Qa6anJRm j9/9nvkviDGWVH2tUl757mLrhFK5RRa2T7n3+rQZWiuI5LECE8QU+J9Op7my2Mvhgp3W iP7YCHFqQ1wD0VCxbncDH1lX8i8ADGp35KYGuyfb5jb72MnKaaOzpjFJ5rOVUkjXZNqR SLtB1ChUirUdWd2hWB2FhjDI05kPNlrsiMQgWrIyI1f3vp5YSTcjhmxQzzeEGpWVucRd 0hYA== 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 x138-20020a633190000000b0050382913ab1si14416850pgx.579.2023.03.07.23.17.29; Tue, 07 Mar 2023 23:17:42 -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 S229695AbjCHHKv (ORCPT <rfc822;toshivichauhan@gmail.com> + 99 others); Wed, 8 Mar 2023 02:10:51 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229610AbjCHHKs (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Wed, 8 Mar 2023 02:10:48 -0500 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 359C540E9; Tue, 7 Mar 2023 23:10:47 -0800 (PST) Received: from dggpemm500013.china.huawei.com (unknown [172.30.72.54]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4PWk3B528JzrST2; Wed, 8 Mar 2023 15:09:58 +0800 (CST) Received: from ubuntu1804.huawei.com (10.67.175.36) by dggpemm500013.china.huawei.com (7.185.36.172) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Wed, 8 Mar 2023 15:10:44 +0800 From: Chen Zhongjin <chenzhongjin@huawei.com> To: <linux-trace-kernel@vger.kernel.org>, <linux-kernel@vger.kernel.org> CC: <chenzhongjin@huawei.com>, <rostedt@goodmis.org>, <mhiramat@kernel.org>, <mark.rutland@arm.com> Subject: [PATCH] ftrace: Add ftrace_page to list after the index is calculated Date: Wed, 8 Mar 2023 15:08:44 +0800 Message-ID: <20230308070844.58180-1-chenzhongjin@huawei.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.67.175.36] X-ClientProxiedBy: dggems705-chm.china.huawei.com (10.3.19.182) To dggpemm500013.china.huawei.com (7.185.36.172) 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?1759783013128307260?= X-GMAIL-MSGID: =?utf-8?q?1759783013128307260?= |
Series |
ftrace: Add ftrace_page to list after the index is calculated
|
|
Commit Message
Chen Zhongjin
March 8, 2023, 7:08 a.m. UTC
KASAN reported follow problem:
BUG: KASAN: use-after-free in lookup_rec
Read of size 8 at addr ffff000199270ff0 by task modprobe
CPU: 2 Comm: modprobe
Hardware name: QEMU KVM Virtual Machine
Call trace:
kasan_report
__asan_load8
lookup_rec
ftrace_location
arch_check_ftrace_location
check_kprobe_address_safe
register_kprobe.part.0
register_kprobe
This happened when lookup_rec accessing pg->records[pg->index - 1].
The accessed position is not a valid records address, it has -16 offset
to the last allocated records page.
In ftrace_process_locs, ftrace_page will be added to ftrace_pages_start
list fist, then its pg->index will be calculated. Before pg->index++,
pg->index == 0.
lookup_rec iterates the whole list if it doesn't find a record. When
there is a page with pg->index == 0, getting pg->records[-1].ip causes
this problem.
Add ftrace_page to the ftrace_pages_start list after pg->index is
calculated, to fix this.
Fixes: 3208230983a0 ("ftrace: Remove usage of "freed" records")
Signed-off-by: Chen Zhongjin <chenzhongjin@huawei.com>
---
kernel/trace/ftrace.c | 35 ++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)
Comments
On Wed, 8 Mar 2023 15:08:44 +0800 Chen Zhongjin <chenzhongjin@huawei.com> wrote: > Fixes: 3208230983a0 ("ftrace: Remove usage of "freed" records") > Signed-off-by: Chen Zhongjin <chenzhongjin@huawei.com> > --- > kernel/trace/ftrace.c | 35 ++++++++++++++++++----------------- > 1 file changed, 18 insertions(+), 17 deletions(-) > > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c > index 29baa97d0d53..a258c48ad91e 100644 > --- a/kernel/trace/ftrace.c > +++ b/kernel/trace/ftrace.c > @@ -6804,28 +6804,14 @@ static int ftrace_process_locs(struct module *mod, > > mutex_lock(&ftrace_lock); > > + if (WARN_ON(mod && !ftrace_pages)) This is wrong. I have no issues with mod && !ftrace_pages. That's not the same as !mod && ftrace_pages, which I want to warn on. The mod && !ftrace_pages means that the system had no ftrace functions but a module does. Strange, but not something to warn about. The !mod && ftrace_pages, means that this is setting up the builtin ftrace pages, but the ftrace_pages already exist. As the builtin needs to only be done once, this is a bug. > + goto out; > + > /* > * Core and each module needs their own pages, as > * modules will free them when they are removed. > * Force a new page to be allocated for modules. > */ > - if (!mod) { > - WARN_ON(ftrace_pages || ftrace_pages_start); > - /* First initialization */ > - ftrace_pages = ftrace_pages_start = start_pg; Since the above only happens at boot up, and before anything can call into it, this is not a problem. > - } else { > - if (!ftrace_pages) > - goto out; > - > - if (WARN_ON(ftrace_pages->next)) { > - /* Hmm, we have free pages? */ > - while (ftrace_pages->next) > - ftrace_pages = ftrace_pages->next; > - } > - > - ftrace_pages->next = start_pg; Basically, what you are saying is that once we add ftrace_pages->next to point to the new start_pg, it becomes visible to others and that could be a problem. And moving this code around is not really going to solve that, as then we would need to add memory barriers. > - } > - > p = start; > pg = start_pg; > while (p < end) { > @@ -6855,6 +6841,21 @@ static int ftrace_process_locs(struct module *mod, > /* We should have used all pages */ > WARN_ON(pg->next); > > + /* Add pages to ftrace_pages list */ > + if (!mod) { > + WARN_ON(ftrace_pages || ftrace_pages_start); > + /* First initialization */ > + ftrace_pages_start = start_pg; > + } else { > + if (WARN_ON(ftrace_pages->next)) { > + /* Hmm, we have free pages? */ > + while (ftrace_pages->next) > + ftrace_pages = ftrace_pages->next; > + } > + > + ftrace_pages->next = start_pg; > + } > + > /* Assign the last page to ftrace_pages */ > ftrace_pages = pg; > Why not just test for it? diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 29baa97d0d53..9b2803c7a18f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1564,7 +1564,8 @@ static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end) key.flags = end; /* overload flags, as it is unsigned long */ for (pg = ftrace_pages_start; pg; pg = pg->next) { - if (end < pg->records[0].ip || + if (pg->index == 0 || + end < pg->records[0].ip || start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE)) continue; rec = bsearch(&key, pg->records, pg->index, -- Steve
On 2023/3/8 22:53, Steven Rostedt wrote: > >> - } else { >> - if (!ftrace_pages) >> - goto out; >> - >> - if (WARN_ON(ftrace_pages->next)) { >> - /* Hmm, we have free pages? */ >> - while (ftrace_pages->next) >> - ftrace_pages = ftrace_pages->next; >> - } >> - >> - ftrace_pages->next = start_pg; > Basically, what you are saying is that once we add ftrace_pages->next to > point to the new start_pg, it becomes visible to others and that could be a > problem. And moving this code around is not really going to solve that, as > then we would need to add memory barriers. > >> - } >> - >> p = start; >> pg = start_pg; >> while (p < end) { >> @@ -6855,6 +6841,21 @@ static int ftrace_process_locs(struct module *mod, >> /* We should have used all pages */ >> WARN_ON(pg->next); >> >> + /* Add pages to ftrace_pages list */ >> + if (!mod) { >> + WARN_ON(ftrace_pages || ftrace_pages_start); >> + /* First initialization */ >> + ftrace_pages_start = start_pg; >> + } else { >> + if (WARN_ON(ftrace_pages->next)) { >> + /* Hmm, we have free pages? */ >> + while (ftrace_pages->next) >> + ftrace_pages = ftrace_pages->next; >> + } >> + >> + ftrace_pages->next = start_pg; >> + } >> + >> /* Assign the last page to ftrace_pages */ >> ftrace_pages = pg; >> > Why not just test for it? > > diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c > index 29baa97d0d53..9b2803c7a18f 100644 > --- a/kernel/trace/ftrace.c > +++ b/kernel/trace/ftrace.c > @@ -1564,7 +1564,8 @@ static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end) > key.flags = end; /* overload flags, as it is unsigned long */ > > for (pg = ftrace_pages_start; pg; pg = pg->next) { > - if (end < pg->records[0].ip || > + if (pg->index == 0 || > + end < pg->records[0].ip || > start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE)) > continue; > rec = bsearch(&key, pg->records, pg->index, > > > -- Steve Thanks for review! At first I'm worried that it will cause lookup_rec to return an incorrect result if it issearching a module address going to be added. But now I found that records are added at MODULE_STATE_UNFORMED, the module address won't be searched at this point in any case. Let's do it this way. I'll send another patch.
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 29baa97d0d53..a258c48ad91e 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -6804,28 +6804,14 @@ static int ftrace_process_locs(struct module *mod, mutex_lock(&ftrace_lock); + if (WARN_ON(mod && !ftrace_pages)) + goto out; + /* * Core and each module needs their own pages, as * modules will free them when they are removed. * Force a new page to be allocated for modules. */ - if (!mod) { - WARN_ON(ftrace_pages || ftrace_pages_start); - /* First initialization */ - ftrace_pages = ftrace_pages_start = start_pg; - } else { - if (!ftrace_pages) - goto out; - - if (WARN_ON(ftrace_pages->next)) { - /* Hmm, we have free pages? */ - while (ftrace_pages->next) - ftrace_pages = ftrace_pages->next; - } - - ftrace_pages->next = start_pg; - } - p = start; pg = start_pg; while (p < end) { @@ -6855,6 +6841,21 @@ static int ftrace_process_locs(struct module *mod, /* We should have used all pages */ WARN_ON(pg->next); + /* Add pages to ftrace_pages list */ + if (!mod) { + WARN_ON(ftrace_pages || ftrace_pages_start); + /* First initialization */ + ftrace_pages_start = start_pg; + } else { + if (WARN_ON(ftrace_pages->next)) { + /* Hmm, we have free pages? */ + while (ftrace_pages->next) + ftrace_pages = ftrace_pages->next; + } + + ftrace_pages->next = start_pg; + } + /* Assign the last page to ftrace_pages */ ftrace_pages = pg;