Skip to content

Commit 0c92c7a

Browse files
liu-song-6rostedt
authored andcommitted
tracing: Fix bad use of igrab in trace_uprobe.c
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. Link: http://lkml.kernel.org/r/[email protected] Fixes: f3f096c ("tracing: Provide trace events interface for uprobes") Fixes: 33ea4b2 ("perf/core: Implement the 'perf_uprobe' PMU") Cc: [email protected] Cc: Ingo Molnar <[email protected]> Cc: Howard McLauchlan <[email protected]> Cc: Josef Bacik <[email protected]> Cc: Srikar Dronamraju <[email protected]> Acked-by: Miklos Szeredi <[email protected]> Reported-by: Miklos Szeredi <[email protected]> Signed-off-by: Song Liu <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 9a0fd67 commit 0c92c7a

File tree

1 file changed

+14
-21
lines changed

1 file changed

+14
-21
lines changed

kernel/trace/trace_uprobe.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct trace_uprobe {
5555
struct list_head list;
5656
struct trace_uprobe_filter filter;
5757
struct uprobe_consumer consumer;
58+
struct path path;
5859
struct inode *inode;
5960
char *filename;
6061
unsigned long offset;
@@ -289,7 +290,7 @@ static void free_trace_uprobe(struct trace_uprobe *tu)
289290
for (i = 0; i < tu->tp.nr_args; i++)
290291
traceprobe_free_probe_arg(&tu->tp.args[i]);
291292

292-
iput(tu->inode);
293+
path_put(&tu->path);
293294
kfree(tu->tp.call.class->system);
294295
kfree(tu->tp.call.name);
295296
kfree(tu->filename);
@@ -363,15 +364,13 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
363364
static int create_trace_uprobe(int argc, char **argv)
364365
{
365366
struct trace_uprobe *tu;
366-
struct inode *inode;
367367
char *arg, *event, *group, *filename;
368368
char buf[MAX_EVENT_NAME_LEN];
369369
struct path path;
370370
unsigned long offset;
371371
bool is_delete, is_return;
372372
int i, ret;
373373

374-
inode = NULL;
375374
ret = 0;
376375
is_delete = false;
377376
is_return = false;
@@ -437,21 +436,16 @@ static int create_trace_uprobe(int argc, char **argv)
437436
}
438437
/* Find the last occurrence, in case the path contains ':' too. */
439438
arg = strrchr(argv[1], ':');
440-
if (!arg) {
441-
ret = -EINVAL;
442-
goto fail_address_parse;
443-
}
439+
if (!arg)
440+
return -EINVAL;
444441

445442
*arg++ = '\0';
446443
filename = argv[1];
447444
ret = kern_path(filename, LOOKUP_FOLLOW, &path);
448445
if (ret)
449-
goto fail_address_parse;
450-
451-
inode = igrab(d_real_inode(path.dentry));
452-
path_put(&path);
446+
return ret;
453447

454-
if (!inode || !S_ISREG(inode->i_mode)) {
448+
if (!d_is_reg(path.dentry)) {
455449
ret = -EINVAL;
456450
goto fail_address_parse;
457451
}
@@ -490,7 +484,7 @@ static int create_trace_uprobe(int argc, char **argv)
490484
goto fail_address_parse;
491485
}
492486
tu->offset = offset;
493-
tu->inode = inode;
487+
tu->path = path;
494488
tu->filename = kstrdup(filename, GFP_KERNEL);
495489

496490
if (!tu->filename) {
@@ -558,7 +552,7 @@ static int create_trace_uprobe(int argc, char **argv)
558552
return ret;
559553

560554
fail_address_parse:
561-
iput(inode);
555+
path_put(&path);
562556

563557
pr_info("Failed to parse address or file.\n");
564558

@@ -922,6 +916,7 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
922916
goto err_flags;
923917

924918
tu->consumer.filter = filter;
919+
tu->inode = d_real_inode(tu->path.dentry);
925920
ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
926921
if (ret)
927922
goto err_buffer;
@@ -967,6 +962,7 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
967962
WARN_ON(!uprobe_filter_is_empty(&tu->filter));
968963

969964
uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
965+
tu->inode = NULL;
970966
tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE;
971967

972968
uprobe_buffer_disable();
@@ -1337,19 +1333,15 @@ struct trace_event_call *
13371333
create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
13381334
{
13391335
struct trace_uprobe *tu;
1340-
struct inode *inode;
13411336
struct path path;
13421337
int ret;
13431338

13441339
ret = kern_path(name, LOOKUP_FOLLOW, &path);
13451340
if (ret)
13461341
return ERR_PTR(ret);
13471342

1348-
inode = igrab(d_inode(path.dentry));
1349-
path_put(&path);
1350-
1351-
if (!inode || !S_ISREG(inode->i_mode)) {
1352-
iput(inode);
1343+
if (!d_is_reg(path.dentry)) {
1344+
path_put(&path);
13531345
return ERR_PTR(-EINVAL);
13541346
}
13551347

@@ -1364,11 +1356,12 @@ create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
13641356
if (IS_ERR(tu)) {
13651357
pr_info("Failed to allocate trace_uprobe.(%d)\n",
13661358
(int)PTR_ERR(tu));
1359+
path_put(&path);
13671360
return ERR_CAST(tu);
13681361
}
13691362

13701363
tu->offset = offs;
1371-
tu->inode = inode;
1364+
tu->path = path;
13721365
tu->filename = kstrdup(name, GFP_KERNEL);
13731366
init_trace_event_call(tu, &tu->tp.call);
13741367

0 commit comments

Comments
 (0)