diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2010-05-26 17:40:29 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-05-27 22:03:08 -0400 |
commit | ea635c64e007061f6468ece5cc9cc62d41d4ecf2 (patch) | |
tree | eaa7123e7749893e8f542d12cba616664bc2c848 | |
parent | d7065da038227a4d09a244e6014e0186a6bd21d0 (diff) |
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>
-rw-r--r-- | kernel/perf_event.c | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index e099650cd249..bd7ce8ca5bb9 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -4999,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open, | |||
4999 | struct perf_event_context *ctx; | 4999 | struct perf_event_context *ctx; |
5000 | struct file *event_file = NULL; | 5000 | struct file *event_file = NULL; |
5001 | struct file *group_file = NULL; | 5001 | struct file *group_file = NULL; |
5002 | int event_fd; | ||
5002 | int fput_needed = 0; | 5003 | int fput_needed = 0; |
5003 | int fput_needed2 = 0; | ||
5004 | int err; | 5004 | int err; |
5005 | 5005 | ||
5006 | /* for future expandability... */ | 5006 | /* for future expandability... */ |
@@ -5021,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open, | |||
5021 | return -EINVAL; | 5021 | return -EINVAL; |
5022 | } | 5022 | } |
5023 | 5023 | ||
5024 | event_fd = get_unused_fd_flags(O_RDWR); | ||
5025 | if (event_fd < 0) | ||
5026 | return event_fd; | ||
5027 | |||
5024 | /* | 5028 | /* |
5025 | * Get the target context (task or percpu): | 5029 | * Get the target context (task or percpu): |
5026 | */ | 5030 | */ |
5027 | ctx = find_get_context(pid, cpu); | 5031 | ctx = find_get_context(pid, cpu); |
5028 | if (IS_ERR(ctx)) | 5032 | if (IS_ERR(ctx)) { |
5029 | return PTR_ERR(ctx); | 5033 | err = PTR_ERR(ctx); |
5034 | goto err_fd; | ||
5035 | } | ||
5030 | 5036 | ||
5031 | /* | 5037 | /* |
5032 | * Look up the group leader (we will attach this event to it): | 5038 | * Look up the group leader (we will attach this event to it): |
@@ -5066,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open, | |||
5066 | if (IS_ERR(event)) | 5072 | if (IS_ERR(event)) |
5067 | goto err_put_context; | 5073 | goto err_put_context; |
5068 | 5074 | ||
5069 | err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR); | 5075 | event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR); |
5070 | if (err < 0) | 5076 | if (IS_ERR(event_file)) { |
5071 | goto err_free_put_context; | 5077 | err = PTR_ERR(event_file); |
5072 | |||
5073 | event_file = fget_light(err, &fput_needed2); | ||
5074 | if (!event_file) | ||
5075 | goto err_free_put_context; | 5078 | goto err_free_put_context; |
5079 | } | ||
5076 | 5080 | ||
5077 | if (flags & PERF_FLAG_FD_OUTPUT) { | 5081 | if (flags & PERF_FLAG_FD_OUTPUT) { |
5078 | err = perf_event_set_output(event, group_fd); | 5082 | err = perf_event_set_output(event, group_fd); |
@@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open, | |||
5093 | list_add_tail(&event->owner_entry, ¤t->perf_event_list); | 5097 | list_add_tail(&event->owner_entry, ¤t->perf_event_list); |
5094 | mutex_unlock(¤t->perf_event_mutex); | 5098 | mutex_unlock(¤t->perf_event_mutex); |
5095 | 5099 | ||
5096 | err_fput_free_put_context: | 5100 | fput_light(group_file, fput_needed); |
5097 | fput_light(event_file, fput_needed2); | 5101 | fd_install(event_fd, event_file); |
5102 | return event_fd; | ||
5098 | 5103 | ||
5104 | err_fput_free_put_context: | ||
5105 | fput(event_file); | ||
5099 | err_free_put_context: | 5106 | err_free_put_context: |
5100 | if (err < 0) | 5107 | free_event(event); |
5101 | free_event(event); | ||
5102 | |||
5103 | err_put_context: | 5108 | err_put_context: |
5104 | if (err < 0) | ||
5105 | put_ctx(ctx); | ||
5106 | |||
5107 | fput_light(group_file, fput_needed); | 5109 | fput_light(group_file, fput_needed); |
5108 | 5110 | put_ctx(ctx); | |
5111 | err_fd: | ||
5112 | put_unused_fd(event_fd); | ||
5109 | return err; | 5113 | return err; |
5110 | } | 5114 | } |
5111 | 5115 | ||