diff options
Diffstat (limited to 'net/socket.c')
| -rw-r--r-- | net/socket.c | 84 | 
1 files changed, 16 insertions, 68 deletions
diff --git a/net/socket.c b/net/socket.c index 8a109012608a..792f0313ea91 100644 --- a/net/socket.c +++ b/net/socket.c @@ -89,6 +89,7 @@  #include <linux/magic.h>  #include <linux/slab.h>  #include <linux/xattr.h> +#include <linux/nospec.h>  #include <linux/uaccess.h>  #include <asm/unistd.h> @@ -117,10 +118,8 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from);  static int sock_mmap(struct file *file, struct vm_area_struct *vma);  static int sock_close(struct inode *inode, struct file *file); -static struct wait_queue_head *sock_get_poll_head(struct file *file, -		__poll_t events); -static __poll_t sock_poll_mask(struct file *file, __poll_t); -static __poll_t sock_poll(struct file *file, struct poll_table_struct *wait); +static __poll_t sock_poll(struct file *file, +			      struct poll_table_struct *wait);  static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg);  #ifdef CONFIG_COMPAT  static long compat_sock_ioctl(struct file *file, @@ -143,8 +142,6 @@ static const struct file_operations socket_file_ops = {  	.llseek =	no_llseek,  	.read_iter =	sock_read_iter,  	.write_iter =	sock_write_iter, -	.get_poll_head = sock_get_poll_head, -	.poll_mask =	sock_poll_mask,  	.poll =		sock_poll,  	.unlocked_ioctl = sock_ioctl,  #ifdef CONFIG_COMPAT @@ -391,39 +388,20 @@ static struct file_system_type sock_fs_type = {  struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname)  { -	struct qstr name = { .name = "" }; -	struct path path;  	struct file *file; -	if (dname) { -		name.name = dname; -		name.len = strlen(name.name); -	} else if (sock->sk) { -		name.name = sock->sk->sk_prot_creator->name; -		name.len = strlen(name.name); -	} -	path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); -	if (unlikely(!path.dentry)) { -		sock_release(sock); -		return ERR_PTR(-ENOMEM); -	} -	path.mnt = mntget(sock_mnt); +	if (!dname) +		dname = sock->sk ? sock->sk->sk_prot_creator->name : ""; -	d_instantiate(path.dentry, SOCK_INODE(sock)); - -	file = alloc_file(&path, FMODE_READ | FMODE_WRITE, -		  &socket_file_ops); +	file = alloc_file_pseudo(SOCK_INODE(sock), sock_mnt, dname, +				O_RDWR | (flags & O_NONBLOCK), +				&socket_file_ops);  	if (IS_ERR(file)) { -		/* drop dentry, keep inode for a bit */ -		ihold(d_inode(path.dentry)); -		path_put(&path); -		/* ... and now kill it properly */  		sock_release(sock);  		return file;  	}  	sock->file = file; -	file->f_flags = O_RDWR | (flags & O_NONBLOCK);  	file->private_data = sock;  	return file;  } @@ -1130,48 +1108,16 @@ out_release:  }  EXPORT_SYMBOL(sock_create_lite); -static struct wait_queue_head *sock_get_poll_head(struct file *file, -		__poll_t events) -{ -	struct socket *sock = file->private_data; - -	if (!sock->ops->poll_mask) -		return NULL; -	sock_poll_busy_loop(sock, events); -	return sk_sleep(sock->sk); -} - -static __poll_t sock_poll_mask(struct file *file, __poll_t events) -{ -	struct socket *sock = file->private_data; - -	/* -	 * We need to be sure we are in sync with the socket flags modification. -	 * -	 * This memory barrier is paired in the wq_has_sleeper. -	 */ -	smp_mb(); - -	/* this socket can poll_ll so tell the system call */ -	return sock->ops->poll_mask(sock, events) | -		(sk_can_busy_loop(sock->sk) ? POLL_BUSY_LOOP : 0); -} -  /* No kernel lock held - perfect */  static __poll_t sock_poll(struct file *file, poll_table *wait)  {  	struct socket *sock = file->private_data; -	__poll_t events = poll_requested_events(wait), mask = 0; - -	if (sock->ops->poll) { -		sock_poll_busy_loop(sock, events); -		mask = sock->ops->poll(file, sock, wait); -	} else if (sock->ops->poll_mask) { -		sock_poll_wait(file, sock_get_poll_head(file, events), wait); -		mask = sock->ops->poll_mask(sock, events); -	} +	__poll_t events = poll_requested_events(wait); -	return mask | sock_poll_busy_flag(sock); +	sock_poll_busy_loop(sock, events); +	if (!sock->ops->poll) +		return 0; +	return sock->ops->poll(file, sock, wait) | sock_poll_busy_flag(sock);  }  static int sock_mmap(struct file *file, struct vm_area_struct *vma) @@ -2558,6 +2504,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)  	if (call < 1 || call > SYS_SENDMMSG)  		return -EINVAL; +	call = array_index_nospec(call, SYS_SENDMMSG + 1);  	len = nargs[call];  	if (len > sizeof(a)) @@ -2724,7 +2671,8 @@ EXPORT_SYMBOL(sock_unregister);  bool sock_is_registered(int family)  { -	return family < NPROTO && rcu_access_pointer(net_families[family]); +	return family < NPROTO && +		rcu_access_pointer(net_families[array_index_nospec(family, NPROTO)]);  }  static int __init sock_init(void)  | 
