Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

Al Viro ea635c64 d7065da0

+24 -20
+24 -20
kernel/perf_event.c
··· 4999 4999 struct perf_event_context *ctx; 5000 5000 struct file *event_file = NULL; 5001 5001 struct file *group_file = NULL; 5002 + int event_fd; 5002 5003 int fput_needed = 0; 5003 - int fput_needed2 = 0; 5004 5004 int err; 5005 5005 5006 5006 /* for future expandability... */ ··· 5021 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 5029 * Get the target context (task or percpu): 5026 5030 */ 5027 5031 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 + } 5030 5036 5031 5037 /* 5032 5038 * Look up the group leader (we will attach this event to it): ··· 5072 5066 if (IS_ERR(event)) 5073 5067 goto err_put_context; 5074 5068 5075 - err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR); 5076 - if (err < 0) 5069 + event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR); 5070 + if (IS_ERR(event_file)) { 5071 + err = PTR_ERR(event_file); 5077 5072 goto err_free_put_context; 5078 - 5079 - event_file = fget_light(err, &fput_needed2); 5080 - if (!event_file) 5081 - goto err_free_put_context; 5073 + } 5082 5074 5083 5075 if (flags & PERF_FLAG_FD_OUTPUT) { 5084 5076 err = perf_event_set_output(event, group_fd); ··· 5097 5093 list_add_tail(&event->owner_entry, &current->perf_event_list); 5098 5094 mutex_unlock(&current->perf_event_mutex); 5099 5095 5100 - err_fput_free_put_context: 5101 - fput_light(event_file, fput_needed2); 5102 - 5103 - err_free_put_context: 5104 - if (err < 0) 5105 - free_event(event); 5106 - 5107 - err_put_context: 5108 - if (err < 0) 5109 - put_ctx(ctx); 5110 - 5111 5096 fput_light(group_file, fput_needed); 5097 + fd_install(event_fd, event_file); 5098 + return event_fd; 5112 5099 5100 + err_fput_free_put_context: 5101 + fput(event_file); 5102 + err_free_put_context: 5103 + free_event(event); 5104 + err_put_context: 5105 + fput_light(group_file, fput_needed); 5106 + put_ctx(ctx); 5107 + err_fd: 5108 + put_unused_fd(event_fd); 5113 5109 return err; 5114 5110 } 5115 5111