forked from mirrors/linux
		
	 6474353a5e
			
		
	
	
		6474353a5e
		
			
		
	
	
	
	
		
			
			Epoll relies on a racy fastpath check during __fput() in eventpoll_release() to avoid the hit of pointlessly acquiring a semaphore. Annotate that race by using WRITE_ONCE() and READ_ONCE(). Link: https://lore.kernel.org/r/66edfb3c.050a0220.3195df.001a.GAE@google.com Link: https://lore.kernel.org/r/20240925-fungieren-anbauen-79b334b00542@brauner Reviewed-by: Jan Kara <jack@suse.cz> Reported-by: syzbot+3b6b32dc50537a49bb4a@syzkaller.appspotmail.com Signed-off-by: Christian Brauner <brauner@kernel.org>
		
			
				
	
	
		
			89 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0-or-later */
 | |
| /*
 | |
|  *  include/linux/eventpoll.h ( Efficient event polling implementation )
 | |
|  *  Copyright (C) 2001,...,2006	 Davide Libenzi
 | |
|  *
 | |
|  *  Davide Libenzi <davidel@xmailserver.org>
 | |
|  */
 | |
| #ifndef _LINUX_EVENTPOLL_H
 | |
| #define _LINUX_EVENTPOLL_H
 | |
| 
 | |
| #include <uapi/linux/eventpoll.h>
 | |
| #include <uapi/linux/kcmp.h>
 | |
| 
 | |
| 
 | |
| /* Forward declarations to avoid compiler errors */
 | |
| struct file;
 | |
| 
 | |
| 
 | |
| #ifdef CONFIG_EPOLL
 | |
| 
 | |
| #ifdef CONFIG_KCMP
 | |
| struct file *get_epoll_tfile_raw_ptr(struct file *file, int tfd, unsigned long toff);
 | |
| #endif
 | |
| 
 | |
| /* Used to release the epoll bits inside the "struct file" */
 | |
| void eventpoll_release_file(struct file *file);
 | |
| 
 | |
| /*
 | |
|  * This is called from inside fs/file_table.c:__fput() to unlink files
 | |
|  * from the eventpoll interface. We need to have this facility to cleanup
 | |
|  * correctly files that are closed without being removed from the eventpoll
 | |
|  * interface.
 | |
|  */
 | |
| static inline void eventpoll_release(struct file *file)
 | |
| {
 | |
| 
 | |
| 	/*
 | |
| 	 * Fast check to avoid the get/release of the semaphore. Since
 | |
| 	 * we're doing this outside the semaphore lock, it might return
 | |
| 	 * false negatives, but we don't care. It'll help in 99.99% of cases
 | |
| 	 * to avoid the semaphore lock. False positives simply cannot happen
 | |
| 	 * because the file in on the way to be removed and nobody ( but
 | |
| 	 * eventpoll ) has still a reference to this file.
 | |
| 	 */
 | |
| 	if (likely(!READ_ONCE(file->f_ep)))
 | |
| 		return;
 | |
| 
 | |
| 	/*
 | |
| 	 * The file is being closed while it is still linked to an epoll
 | |
| 	 * descriptor. We need to handle this by correctly unlinking it
 | |
| 	 * from its containers.
 | |
| 	 */
 | |
| 	eventpoll_release_file(file);
 | |
| }
 | |
| 
 | |
| int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
 | |
| 		 bool nonblock);
 | |
| 
 | |
| /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
 | |
| static inline int ep_op_has_event(int op)
 | |
| {
 | |
| 	return op != EPOLL_CTL_DEL;
 | |
| }
 | |
| 
 | |
| #else
 | |
| 
 | |
| static inline void eventpoll_release(struct file *file) {}
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(CONFIG_ARM) && defined(CONFIG_OABI_COMPAT)
 | |
| /* ARM OABI has an incompatible struct layout and needs a special handler */
 | |
| extern struct epoll_event __user *
 | |
| epoll_put_uevent(__poll_t revents, __u64 data,
 | |
| 		 struct epoll_event __user *uevent);
 | |
| #else
 | |
| static inline struct epoll_event __user *
 | |
| epoll_put_uevent(__poll_t revents, __u64 data,
 | |
| 		 struct epoll_event __user *uevent)
 | |
| {
 | |
| 	if (__put_user(revents, &uevent->events) ||
 | |
| 	    __put_user(data, &uevent->data))
 | |
| 		return NULL;
 | |
| 
 | |
| 	return uevent+1;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #endif /* #ifndef _LINUX_EVENTPOLL_H */
 |