Skip to content

Commit

Permalink
Fix racy use of anon_inode_getfd() in perf_event.c
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed May 28, 2010
1 parent d7065da commit ea635c6
Showing 1 changed file with 22 additions and 18 deletions.
40 changes: 22 additions & 18 deletions kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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... */
Expand All @@ -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):
Expand Down Expand Up @@ -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);
Expand All @@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open,
list_add_tail(&event->owner_entry, &current->perf_event_list);
mutex_unlock(&current->perf_event_mutex);

err_fput_free_put_context:
fput_light(event_file, fput_needed2);
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:
if (err < 0)
free_event(event);

free_event(event);
err_put_context:
if (err < 0)
put_ctx(ctx);

fput_light(group_file, fput_needed);

put_ctx(ctx);
err_fd:
put_unused_fd(event_fd);
return err;
}

Expand Down

0 comments on commit ea635c6

Please sign in to comment.