Fix racy use of anon_inode_getfd() in perf_event.c
once anon_inode_getfd() is called, you can't expect *anything* about struct file that descriptor points to - another thread might be doing whatever it likes with descriptor table at that point. Cc: stable <stable@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
d7065da038
commit
ea635c64e0
|
@ -4999,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
struct perf_event_context *ctx;
|
||||
struct file *event_file = NULL;
|
||||
struct file *group_file = NULL;
|
||||
int event_fd;
|
||||
int fput_needed = 0;
|
||||
int fput_needed2 = 0;
|
||||
int err;
|
||||
|
||||
/* for future expandability... */
|
||||
|
@ -5021,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
event_fd = get_unused_fd_flags(O_RDWR);
|
||||
if (event_fd < 0)
|
||||
return event_fd;
|
||||
|
||||
/*
|
||||
* Get the target context (task or percpu):
|
||||
*/
|
||||
ctx = find_get_context(pid, cpu);
|
||||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
if (IS_ERR(ctx)) {
|
||||
err = PTR_ERR(ctx);
|
||||
goto err_fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the group leader (we will attach this event to it):
|
||||
|
@ -5066,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
if (IS_ERR(event))
|
||||
goto err_put_context;
|
||||
|
||||
err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR);
|
||||
if (err < 0)
|
||||
goto err_free_put_context;
|
||||
|
||||
event_file = fget_light(err, &fput_needed2);
|
||||
if (!event_file)
|
||||
event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
|
||||
if (IS_ERR(event_file)) {
|
||||
err = PTR_ERR(event_file);
|
||||
goto err_free_put_context;
|
||||
}
|
||||
|
||||
if (flags & PERF_FLAG_FD_OUTPUT) {
|
||||
err = perf_event_set_output(event, group_fd);
|
||||
|
@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open,
|
|||
list_add_tail(&event->owner_entry, ¤t->perf_event_list);
|
||||
mutex_unlock(¤t->perf_event_mutex);
|
||||
|
||||
err_fput_free_put_context:
|
||||
fput_light(event_file, fput_needed2);
|
||||
|
||||
err_free_put_context:
|
||||
if (err < 0)
|
||||
free_event(event);
|
||||
|
||||
err_put_context:
|
||||
if (err < 0)
|
||||
put_ctx(ctx);
|
||||
|
||||
fput_light(group_file, fput_needed);
|
||||
fd_install(event_fd, event_file);
|
||||
return event_fd;
|
||||
|
||||
err_fput_free_put_context:
|
||||
fput(event_file);
|
||||
err_free_put_context:
|
||||
free_event(event);
|
||||
err_put_context:
|
||||
fput_light(group_file, fput_needed);
|
||||
put_ctx(ctx);
|
||||
err_fd:
|
||||
put_unused_fd(event_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue