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 /kernel/perf_event.c | |
| 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>
Diffstat (limited to 'kernel/perf_event.c')
| -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 | ||
