Received: by 10.192.165.148 with SMTP id m20csp3228153imm; Mon, 23 Apr 2018 02:57:39 -0700 (PDT) X-Google-Smtp-Source: AIpwx498r1rFYFjfVxNaMH6raIijeXcXJ5PtYvpJ674hYl1Lebcuo5aKwrnAZMGwh94hEBfMit4j X-Received: by 10.98.80.80 with SMTP id e77mr19586439pfb.16.1524477459402; Mon, 23 Apr 2018 02:57:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524477459; cv=none; d=google.com; s=arc-20160816; b=kQJnr+dMavWkTxl1WEvJcHj5pw4+R80H/ALxaaVSM1RCFsw2Y42F9Bhtom7KCTMqg5 JkRLjvlNG5x6LHKE4QN1TcSO3f0eKwiSkIZ7LBcbw8aOk9BQRaR9cTG7sTDT6wxvVsPH o3ni21yJjz1IeXFx7HmM7FoElqa/pOXzZMLekRCIAKmA8UBVUdD5+XOLsjtoj17kV8CB aqqg3lRW+XCsVOnii0vCY09wpsi3lPFIHGfELThac1X39Ohvv09E8nslteS+KqnywbS8 40j2Tv54X8yp8jTrc9u8FSz5gAyndJVmcJCAW2wDQDl6T7HUNFQ3jczGMk9Bws4HoSKa ymHA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=Ok0kPcoSFEV8vPO8CLpNy3bi8m7F0oRcszSUd78pSBY=; b=Oh4QfKfWeFpMyYhJO4Swnh9fbggQIpbvVM/diemYgL/CRbAZGwRZLHNluKsC6uFsjw HYsDx2aaTrsPHf75SoZcBbXiywb7COExpmyS53DaQ4e/OitSpzTRyz4OTF4AL+hg0lQ3 CTdGJf1GVP+G96nz7ZzNnigUk0gZwuXq6qOIlFL6+2ddAiAyxzb8eLDuraNTW9BxT/yt mdtqrbwpVMjT5DguexSBhTzsUYpXsk1tCArEJHy1UinWpNwV7NoaZQ+SwR+nzGfn864N 2jZ8RxzeYj7ZzydwlyxkeW2HzyN0JC6uz7X8dc9gCj96MXsTxv1VvhVF0QpvFSck8N4H Q3zg== ARC-Authentication-Results: i=1; mx.google.com; dkim=temperror (no key for signature) header.i=@szeredi.hu header.s=google header.b=eUnDsjrh; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s5-v6si11456434plp.139.2018.04.23.02.57.24; Mon, 23 Apr 2018 02:57:39 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=temperror (no key for signature) header.i=@szeredi.hu header.s=google header.b=eUnDsjrh; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754584AbeDWJ4H (ORCPT + 99 others); Mon, 23 Apr 2018 05:56:07 -0400 Received: from mail-oi0-f66.google.com ([209.85.218.66]:41479 "EHLO mail-oi0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754327AbeDWJ4G (ORCPT ); Mon, 23 Apr 2018 05:56:06 -0400 Received: by mail-oi0-f66.google.com with SMTP id 188-v6so13689253oih.8 for ; Mon, 23 Apr 2018 02:56:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=szeredi.hu; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=Ok0kPcoSFEV8vPO8CLpNy3bi8m7F0oRcszSUd78pSBY=; b=eUnDsjrhDgJg9AVxvlNgxlKidizlYuFOZwNSK8UBEMcStjuBCoyiRukyqiGLgC9ogQ Hy9zAKXAspJaxPWTueQtx81ZVQ7GyBiIiLbBXyz+r/lNcO/YtTgvtqNWTx4ZOJ+MV2N+ XgCa1SFQ+PN27JyafKKNEY6YtwX2g0pYiKfVM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=Ok0kPcoSFEV8vPO8CLpNy3bi8m7F0oRcszSUd78pSBY=; b=fQc/MeeUmzId7upwF05EHHns8GxttxyJlGVEwhRqSB3Kw5hy6SsHtGVUavZMj9M9Af fjzyWq1ANxatplxJ3sE6F17sJdSuJ0LHFNlgDd7rQcSqSx859dNgr8YdoHX2NSShffMv xwChSQ0bDKMUwQHwGEU4ghOA3FPlmg9acFEc6fWNeUXOsjeV9qFxQfspXE4sRzonGOJS j0YWZUWTWTQn5ppLiD2USUWPyh4AmqthlNDeAzpWH+jE6+rTfPw2Tezy/jAwvYwio0Nz CgO7sfTr4M4Oqm5FjYPifAYrSPVafH1NfU7tEIXqtFssj7wHvG8WLmIXv4wCd61yuT+7 /x0Q== X-Gm-Message-State: ALQs6tBDDhBdGPfJlCGp7dmCieFFf+IJMVHy4KpxsJj5pNnTQpqWsgTi GcmAGUUHnMbMNXmTe4rvXRsNQC7IX2Z0tS5EXntEpw== X-Received: by 2002:aca:a610:: with SMTP id p16-v6mr11693306oie.149.1524477365489; Mon, 23 Apr 2018 02:56:05 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a9d:5303:0:0:0:0:0 with HTTP; Mon, 23 Apr 2018 02:56:04 -0700 (PDT) X-Originating-IP: [176.63.54.97] In-Reply-To: <20180420165625.129593-1-songliubraving@fb.com> References: <20180420165625.129593-1-songliubraving@fb.com> From: Miklos Szeredi Date: Mon, 23 Apr 2018 11:56:04 +0200 Message-ID: Subject: Re: [PATCH v3 1/2] tracing: fix bad use of igrab in trace_uprobe.c To: Song Liu Cc: linux-kernel@vger.kernel.org, kernel-team , Steven Rostedt , Ingo Molnar , Howard McLauchlan , Josef Bacik , Srikar Dronamraju Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, Apr 20, 2018 at 6:56 PM, Song Liu wrote: > As Miklos reported and suggested: > > This pattern repeats two times in trace_uprobe.c and in > kernel/events/core.c as well: > > ret = kern_path(filename, LOOKUP_FOLLOW, &path); > if (ret) > goto fail_address_parse; > > inode = igrab(d_inode(path.dentry)); > path_put(&path); > > And it's wrong. You can only hold a reference to the inode if you > have an active ref to the superblock as well (which is normally > through path.mnt) or holding s_umount. > > This way unmounting the containing filesystem while the tracepoint is > active will give you the "VFS: Busy inodes after unmount..." message > and a crash when the inode is finally put. > > Solution: store path instead of inode. > > This patch fixes two instances in trace_uprobe.c. struct path is added to > struct trace_uprobe to keep the inode and containing mount point > referenced. > > Fixes: f3f096cfedf8 ("tracing: Provide trace events interface for uprobes") > Fixes: 33ea4b24277b ("perf/core: Implement the 'perf_uprobe' PMU") > Cc: Steven Rostedt > Cc: Ingo Molnar > Cc: Howard McLauchlan > Cc: Josef Bacik > Cc: Srikar Dronamraju > Cc: Miklos Szeredi > Reported-by: Miklos Szeredi > Signed-off-by: Song Liu > --- > kernel/trace/trace_uprobe.c | 55 +++++++++++++++++++-------------------------- > 1 file changed, 23 insertions(+), 32 deletions(-) > > diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c > index 34fd0e0..e7ffb5e 100644 > --- a/kernel/trace/trace_uprobe.c > +++ b/kernel/trace/trace_uprobe.c > @@ -55,6 +55,7 @@ struct trace_uprobe { > struct list_head list; > struct trace_uprobe_filter filter; > struct uprobe_consumer consumer; > + struct path path; > struct inode *inode; > char *filename; > unsigned long offset; > @@ -289,7 +290,7 @@ static void free_trace_uprobe(struct trace_uprobe *tu) > for (i = 0; i < tu->tp.nr_args; i++) > traceprobe_free_probe_arg(&tu->tp.args[i]); > > - iput(tu->inode); > + path_put(&tu->path); > kfree(tu->tp.call.class->system); > kfree(tu->tp.call.name); > kfree(tu->filename); > @@ -363,7 +364,6 @@ static int register_trace_uprobe(struct trace_uprobe *tu) > static int create_trace_uprobe(int argc, char **argv) > { > struct trace_uprobe *tu; > - struct inode *inode; > char *arg, *event, *group, *filename; > char buf[MAX_EVENT_NAME_LEN]; > struct path path; > @@ -371,7 +371,6 @@ static int create_trace_uprobe(int argc, char **argv) > bool is_delete, is_return; > int i, ret; > > - inode = NULL; > ret = 0; > is_delete = false; > is_return = false; > @@ -437,24 +436,14 @@ static int create_trace_uprobe(int argc, char **argv) > } > /* Find the last occurrence, in case the path contains ':' too. */ > arg = strrchr(argv[1], ':'); > - if (!arg) { > - ret = -EINVAL; > - goto fail_address_parse; > - } > + if (!arg) > + return -EINVAL; > > *arg++ = '\0'; > filename = argv[1]; > ret = kern_path(filename, LOOKUP_FOLLOW, &path); > if (ret) > - goto fail_address_parse; > - > - inode = igrab(d_real_inode(path.dentry)); > - path_put(&path); > - > - if (!inode || !S_ISREG(inode->i_mode)) { You probably should test for positive regular file here. You can use d_is_reg(path.dentry) for that, which actually checks both the above conditions and ensures that latter you don't even need to test and error out on the !inode case because that is simply impossible. > - ret = -EINVAL; > - goto fail_address_parse; > - } > + return ret; > > ret = kstrtoul(arg, 0, &offset); > if (ret) > @@ -490,7 +479,7 @@ static int create_trace_uprobe(int argc, char **argv) > goto fail_address_parse; > } > tu->offset = offset; > - tu->inode = inode; > + tu->path = path; > tu->filename = kstrdup(filename, GFP_KERNEL); > > if (!tu->filename) { > @@ -558,7 +547,7 @@ static int create_trace_uprobe(int argc, char **argv) > return ret; > > fail_address_parse: > - iput(inode); > + path_put(&path); > > pr_info("Failed to parse address or file.\n"); > > @@ -922,7 +911,14 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file, > goto err_flags; > > tu->consumer.filter = filter; > - ret = uprobe_register(tu->inode, tu->offset, &tu->consumer); > + tu->inode = d_real_inode(tu->path.dentry); > + if (!tu->inode || !S_ISREG(tu->inode->i_mode)) { > + tu->inode = NULL; > + ret = -EINVAL; > + goto err_buffer; > + } > + ret = uprobe_register(tu->inode, tu->offset, > + &tu->consumer); So this just becomes: + tu->inode = d_real_inode(tu->path.dentry); No more changes necessary. > if (ret) > goto err_buffer; > > @@ -966,7 +962,8 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file) > > WARN_ON(!uprobe_filter_is_empty(&tu->filter)); > > - uprobe_unregister(tu->inode, tu->offset, &tu->consumer); > + uprobe_unregister(d_inode(tu->path.dentry), tu->offset, &tu->consumer); Huh? This should also be using tu->inode. Othewise what's the point in storing it? > + tu->inode = NULL; > tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE; > > uprobe_buffer_disable(); > @@ -1041,7 +1038,8 @@ static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) > write_unlock(&tu->filter.rwlock); > > if (!done) > - return uprobe_apply(tu->inode, tu->offset, &tu->consumer, false); > + return uprobe_apply(d_inode(tu->path.dentry), tu->offset, > + &tu->consumer, false); And here. > > return 0; > } > @@ -1073,7 +1071,8 @@ static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) > > err = 0; > if (!done) { > - err = uprobe_apply(tu->inode, tu->offset, &tu->consumer, true); > + err = uprobe_apply(d_inode(tu->path.dentry), > + tu->offset, &tu->consumer, true); And here. Just drop these hunks completely. Using tu->inode is fine. > if (err) > uprobe_perf_close(tu, event); > } > @@ -1337,7 +1336,6 @@ struct trace_event_call * > create_local_trace_uprobe(char *name, unsigned long offs, bool is_return) > { > struct trace_uprobe *tu; > - struct inode *inode; > struct path path; > int ret; > > @@ -1345,14 +1343,6 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return) > if (ret) > return ERR_PTR(ret); > > - inode = igrab(d_inode(path.dentry)); > - path_put(&path); > - > - if (!inode || !S_ISREG(inode->i_mode)) { > - iput(inode); > - return ERR_PTR(-EINVAL); > - } And again, the test for being a regular file can stay here. > - > /* > * local trace_kprobes are not added to probe_list, so they are never > * searched in find_trace_kprobe(). Therefore, there is no concern of > @@ -1364,11 +1354,12 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return) > if (IS_ERR(tu)) { > pr_info("Failed to allocate trace_uprobe.(%d)\n", > (int)PTR_ERR(tu)); > + path_put(&path); > return ERR_CAST(tu); > } > > tu->offset = offs; > - tu->inode = inode; > + tu->path = path; > tu->filename = kstrdup(name, GFP_KERNEL); > init_trace_event_call(tu, &tu->tp.call); > > -- > 2.9.5 >