Commit ea635c64 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent d7065da0
...@@ -4999,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -4999,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open,
struct perf_event_context *ctx; struct perf_event_context *ctx;
struct file *event_file = NULL; struct file *event_file = NULL;
struct file *group_file = NULL; struct file *group_file = NULL;
int event_fd;
int fput_needed = 0; int fput_needed = 0;
int fput_needed2 = 0;
int err; int err;
/* for future expandability... */ /* for future expandability... */
...@@ -5021,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -5021,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open,
return -EINVAL; return -EINVAL;
} }
event_fd = get_unused_fd_flags(O_RDWR);
if (event_fd < 0)
return event_fd;
/* /*
* Get the target context (task or percpu): * Get the target context (task or percpu):
*/ */
ctx = find_get_context(pid, cpu); ctx = find_get_context(pid, cpu);
if (IS_ERR(ctx)) if (IS_ERR(ctx)) {
return PTR_ERR(ctx); err = PTR_ERR(ctx);
goto err_fd;
}
/* /*
* Look up the group leader (we will attach this event to it): * Look up the group leader (we will attach this event to it):
...@@ -5066,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -5066,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open,
if (IS_ERR(event)) if (IS_ERR(event))
goto err_put_context; goto err_put_context;
err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR); event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
if (err < 0) if (IS_ERR(event_file)) {
goto err_free_put_context; err = PTR_ERR(event_file);
event_file = fget_light(err, &fput_needed2);
if (!event_file)
goto err_free_put_context; goto err_free_put_context;
}
if (flags & PERF_FLAG_FD_OUTPUT) { if (flags & PERF_FLAG_FD_OUTPUT) {
err = perf_event_set_output(event, group_fd); err = perf_event_set_output(event, group_fd);
...@@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open,
list_add_tail(&event->owner_entry, &current->perf_event_list); list_add_tail(&event->owner_entry, &current->perf_event_list);
mutex_unlock(&current->perf_event_mutex); mutex_unlock(&current->perf_event_mutex);
err_fput_free_put_context: fput_light(group_file, fput_needed);
fput_light(event_file, fput_needed2); fd_install(event_fd, event_file);
return event_fd;
err_fput_free_put_context:
fput(event_file);
err_free_put_context: err_free_put_context:
if (err < 0)
free_event(event); free_event(event);
err_put_context: err_put_context:
if (err < 0)
put_ctx(ctx);
fput_light(group_file, fput_needed); fput_light(group_file, fput_needed);
put_ctx(ctx);
err_fd:
put_unused_fd(event_fd);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment