Skip to content

Commit ea635c6

Browse files
author
Al Viro
committed
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 <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent d7065da commit ea635c6

File tree

1 file changed

+22
-18
lines changed

1 file changed

+22
-18
lines changed

kernel/perf_event.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4999,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open,
49994999
struct perf_event_context *ctx;
50005000
struct file *event_file = NULL;
50015001
struct file *group_file = NULL;
5002+
int event_fd;
50025003
int fput_needed = 0;
5003-
int fput_needed2 = 0;
50045004
int err;
50055005

50065006
/* for future expandability... */
@@ -5021,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open,
50215021
return -EINVAL;
50225022
}
50235023

5024+
event_fd = get_unused_fd_flags(O_RDWR);
5025+
if (event_fd < 0)
5026+
return event_fd;
5027+
50245028
/*
50255029
* Get the target context (task or percpu):
50265030
*/
50275031
ctx = find_get_context(pid, cpu);
5028-
if (IS_ERR(ctx))
5029-
return PTR_ERR(ctx);
5032+
if (IS_ERR(ctx)) {
5033+
err = PTR_ERR(ctx);
5034+
goto err_fd;
5035+
}
50305036

50315037
/*
50325038
* Look up the group leader (we will attach this event to it):
@@ -5066,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open,
50665072
if (IS_ERR(event))
50675073
goto err_put_context;
50685074

5069-
err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR);
5070-
if (err < 0)
5071-
goto err_free_put_context;
5072-
5073-
event_file = fget_light(err, &fput_needed2);
5074-
if (!event_file)
5075+
event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
5076+
if (IS_ERR(event_file)) {
5077+
err = PTR_ERR(event_file);
50755078
goto err_free_put_context;
5079+
}
50765080

50775081
if (flags & PERF_FLAG_FD_OUTPUT) {
50785082
err = perf_event_set_output(event, group_fd);
@@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open,
50935097
list_add_tail(&event->owner_entry, &current->perf_event_list);
50945098
mutex_unlock(&current->perf_event_mutex);
50955099

5096-
err_fput_free_put_context:
5097-
fput_light(event_file, fput_needed2);
5100+
fput_light(group_file, fput_needed);
5101+
fd_install(event_fd, event_file);
5102+
return event_fd;
50985103

5104+
err_fput_free_put_context:
5105+
fput(event_file);
50995106
err_free_put_context:
5100-
if (err < 0)
5101-
free_event(event);
5102-
5107+
free_event(event);
51035108
err_put_context:
5104-
if (err < 0)
5105-
put_ctx(ctx);
5106-
51075109
fput_light(group_file, fput_needed);
5108-
5110+
put_ctx(ctx);
5111+
err_fd:
5112+
put_unused_fd(event_fd);
51095113
return err;
51105114
}
51115115

0 commit comments

Comments
 (0)