diff options
Diffstat (limited to 'net/core/sock.c')
| -rw-r--r-- | net/core/sock.c | 185 | 
1 files changed, 82 insertions, 103 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 6c4acf1f0220..e4f40b175acb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -113,6 +113,7 @@  #include <linux/static_key.h>  #include <linux/memcontrol.h>  #include <linux/prefetch.h> +#include <linux/compat.h>  #include <linux/uaccess.h> @@ -360,7 +361,8 @@ static int sock_get_timeout(long timeo, void *optval, bool old_timeval)  	return sizeof(tv);  } -static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen, bool old_timeval) +static int sock_set_timeout(long *timeo_p, sockptr_t optval, int optlen, +			    bool old_timeval)  {  	struct __kernel_sock_timeval tv; @@ -370,7 +372,7 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen, bool  		if (optlen < sizeof(tv32))  			return -EINVAL; -		if (copy_from_user(&tv32, optval, sizeof(tv32))) +		if (copy_from_sockptr(&tv32, optval, sizeof(tv32)))  			return -EFAULT;  		tv.tv_sec = tv32.tv_sec;  		tv.tv_usec = tv32.tv_usec; @@ -379,14 +381,14 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen, bool  		if (optlen < sizeof(old_tv))  			return -EINVAL; -		if (copy_from_user(&old_tv, optval, sizeof(old_tv))) +		if (copy_from_sockptr(&old_tv, optval, sizeof(old_tv)))  			return -EFAULT;  		tv.tv_sec = old_tv.tv_sec;  		tv.tv_usec = old_tv.tv_usec;  	} else {  		if (optlen < sizeof(tv))  			return -EINVAL; -		if (copy_from_user(&tv, optval, sizeof(tv))) +		if (copy_from_sockptr(&tv, optval, sizeof(tv)))  			return -EFAULT;  	}  	if (tv.tv_usec < 0 || tv.tv_usec >= USEC_PER_SEC) @@ -608,8 +610,7 @@ int sock_bindtoindex(struct sock *sk, int ifindex, bool lock_sk)  }  EXPORT_SYMBOL(sock_bindtoindex); -static int sock_setbindtodevice(struct sock *sk, char __user *optval, -				int optlen) +static int sock_setbindtodevice(struct sock *sk, sockptr_t optval, int optlen)  {  	int ret = -ENOPROTOOPT;  #ifdef CONFIG_NETDEVICES @@ -631,7 +632,7 @@ static int sock_setbindtodevice(struct sock *sk, char __user *optval,  	memset(devname, 0, sizeof(devname));  	ret = -EFAULT; -	if (copy_from_user(devname, optval, optlen)) +	if (copy_from_sockptr(devname, optval, optlen))  		goto out;  	index = 0; @@ -695,15 +696,6 @@ out:  	return ret;  } -static inline void sock_valbool_flag(struct sock *sk, enum sock_flags bit, -				     int valbool) -{ -	if (valbool) -		sock_set_flag(sk, bit); -	else -		sock_reset_flag(sk, bit); -} -  bool sk_mc_loop(struct sock *sk)  {  	if (dev_recursion_level()) @@ -718,7 +710,7 @@ bool sk_mc_loop(struct sock *sk)  		return inet6_sk(sk)->mc_loop;  #endif  	} -	WARN_ON(1); +	WARN_ON_ONCE(1);  	return true;  }  EXPORT_SYMBOL(sk_mc_loop); @@ -828,13 +820,21 @@ void sock_set_rcvbuf(struct sock *sk, int val)  }  EXPORT_SYMBOL(sock_set_rcvbuf); +void sock_set_mark(struct sock *sk, u32 val) +{ +	lock_sock(sk); +	sk->sk_mark = val; +	release_sock(sk); +} +EXPORT_SYMBOL(sock_set_mark); +  /*   *	This is meant for all protocols to use and covers goings on   *	at the socket level. Everything here is generic.   */  int sock_setsockopt(struct socket *sock, int level, int optname, -		    char __user *optval, unsigned int optlen) +		    sockptr_t optval, unsigned int optlen)  {  	struct sock_txtime sk_txtime;  	struct sock *sk = sock->sk; @@ -853,7 +853,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,  	if (optlen < sizeof(int))  		return -EINVAL; -	if (get_user(val, (int __user *)optval)) +	if (copy_from_sockptr(&val, optval, sizeof(val)))  		return -EFAULT;  	valbool = val ? 1 : 0; @@ -966,7 +966,7 @@ set_sndbuf:  			ret = -EINVAL;	/* 1003.1g */  			break;  		} -		if (copy_from_user(&ling, optval, sizeof(ling))) { +		if (copy_from_sockptr(&ling, optval, sizeof(ling))) {  			ret = -EFAULT;  			break;  		} @@ -1060,60 +1060,52 @@ set_sndbuf:  	case SO_RCVTIMEO_OLD:  	case SO_RCVTIMEO_NEW: -		ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen, optname == SO_RCVTIMEO_OLD); +		ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, +				       optlen, optname == SO_RCVTIMEO_OLD);  		break;  	case SO_SNDTIMEO_OLD:  	case SO_SNDTIMEO_NEW: -		ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen, optname == SO_SNDTIMEO_OLD); +		ret = sock_set_timeout(&sk->sk_sndtimeo, optval, +				       optlen, optname == SO_SNDTIMEO_OLD);  		break; -	case SO_ATTACH_FILTER: -		ret = -EINVAL; -		if (optlen == sizeof(struct sock_fprog)) { -			struct sock_fprog fprog; - -			ret = -EFAULT; -			if (copy_from_user(&fprog, optval, sizeof(fprog))) -				break; +	case SO_ATTACH_FILTER: { +		struct sock_fprog fprog; +		ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); +		if (!ret)  			ret = sk_attach_filter(&fprog, sk); -		}  		break; - +	}  	case SO_ATTACH_BPF:  		ret = -EINVAL;  		if (optlen == sizeof(u32)) {  			u32 ufd;  			ret = -EFAULT; -			if (copy_from_user(&ufd, optval, sizeof(ufd))) +			if (copy_from_sockptr(&ufd, optval, sizeof(ufd)))  				break;  			ret = sk_attach_bpf(ufd, sk);  		}  		break; -	case SO_ATTACH_REUSEPORT_CBPF: -		ret = -EINVAL; -		if (optlen == sizeof(struct sock_fprog)) { -			struct sock_fprog fprog; - -			ret = -EFAULT; -			if (copy_from_user(&fprog, optval, sizeof(fprog))) -				break; +	case SO_ATTACH_REUSEPORT_CBPF: { +		struct sock_fprog fprog; +		ret = copy_bpf_fprog_from_user(&fprog, optval, optlen); +		if (!ret)  			ret = sk_reuseport_attach_filter(&fprog, sk); -		}  		break; - +	}  	case SO_ATTACH_REUSEPORT_EBPF:  		ret = -EINVAL;  		if (optlen == sizeof(u32)) {  			u32 ufd;  			ret = -EFAULT; -			if (copy_from_user(&ufd, optval, sizeof(ufd))) +			if (copy_from_sockptr(&ufd, optval, sizeof(ufd)))  				break;  			ret = sk_reuseport_attach_bpf(ufd, sk); @@ -1193,7 +1185,7 @@ set_sndbuf:  		if (sizeof(ulval) != sizeof(val) &&  		    optlen >= sizeof(ulval) && -		    get_user(ulval, (unsigned long __user *)optval)) { +		    copy_from_sockptr(&ulval, optval, sizeof(ulval))) {  			ret = -EFAULT;  			break;  		} @@ -1236,7 +1228,7 @@ set_sndbuf:  		if (optlen != sizeof(struct sock_txtime)) {  			ret = -EINVAL;  			break; -		} else if (copy_from_user(&sk_txtime, optval, +		} else if (copy_from_sockptr(&sk_txtime, optval,  			   sizeof(struct sock_txtime))) {  			ret = -EFAULT;  			break; @@ -1767,6 +1759,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,  		cgroup_sk_alloc(&sk->sk_cgrp_data);  		sock_update_classid(&sk->sk_cgrp_data);  		sock_update_netprioidx(&sk->sk_cgrp_data); +		sk_tx_queue_clear(sk);  	}  	return sk; @@ -1925,7 +1918,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)  		/* sk->sk_memcg will be populated at accept() time */  		newsk->sk_memcg = NULL; -		cgroup_sk_alloc(&newsk->sk_cgrp_data); +		cgroup_sk_clone(&newsk->sk_cgrp_data);  		rcu_read_lock();  		filter = rcu_dereference(sk->sk_filter); @@ -1972,7 +1965,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)  		/*  		 * Before updating sk_refcnt, we must commit prior changes to memory -		 * (Documentation/RCU/rculist_nulls.txt for details) +		 * (Documentation/RCU/rculist_nulls.rst for details)  		 */  		smp_wmb();  		refcount_set(&newsk->sk_refcnt, 2); @@ -1990,6 +1983,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)  		 */  		sk_refcnt_debug_inc(newsk);  		sk_set_socket(newsk, NULL); +		sk_tx_queue_clear(newsk);  		RCU_INIT_POINTER(newsk->sk_wq, NULL);  		if (newsk->sk_prot->sockets_allocated) @@ -2271,7 +2265,7 @@ static inline void __sock_kfree_s(struct sock *sk, void *mem, int size,  	if (WARN_ON_ONCE(!mem))  		return;  	if (nullify) -		kzfree(mem); +		kfree_sensitive(mem);  	else  		kfree(mem);  	atomic_sub(size, &sk->sk_omem_alloc); @@ -2800,20 +2794,6 @@ int sock_no_shutdown(struct socket *sock, int how)  }  EXPORT_SYMBOL(sock_no_shutdown); -int sock_no_setsockopt(struct socket *sock, int level, int optname, -		    char __user *optval, unsigned int optlen) -{ -	return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_setsockopt); - -int sock_no_getsockopt(struct socket *sock, int level, int optname, -		    char __user *optval, int __user *optlen) -{ -	return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_getsockopt); -  int sock_no_sendmsg(struct socket *sock, struct msghdr *m, size_t len)  {  	return -EOPNOTSUPP; @@ -2840,6 +2820,27 @@ int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *  }  EXPORT_SYMBOL(sock_no_mmap); +/* + * When a file is received (via SCM_RIGHTS, etc), we must bump the + * various sock-based usage counts. + */ +void __receive_sock(struct file *file) +{ +	struct socket *sock; +	int error; + +	/* +	 * The resulting value of "error" is ignored here since we only +	 * need to take action when the file is a socket and testing +	 * "sock" for NULL is sufficient. +	 */ +	sock = sock_from_file(file, &error); +	if (sock) { +		sock_update_netprioidx(&sock->sk->sk_cgrp_data); +		sock_update_classid(&sock->sk->sk_cgrp_data); +	} +} +  ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)  {  	ssize_t res; @@ -3033,7 +3034,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)  	sk_rx_queue_clear(sk);  	/*  	 * Before updating sk_refcnt, we must commit prior changes to memory -	 * (Documentation/RCU/rculist_nulls.txt for details) +	 * (Documentation/RCU/rculist_nulls.rst for details)  	 */  	smp_wmb();  	refcount_set(&sk->sk_refcnt, 1); @@ -3220,20 +3221,6 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname,  }  EXPORT_SYMBOL(sock_common_getsockopt); -#ifdef CONFIG_COMPAT -int compat_sock_common_getsockopt(struct socket *sock, int level, int optname, -				  char __user *optval, int __user *optlen) -{ -	struct sock *sk = sock->sk; - -	if (sk->sk_prot->compat_getsockopt != NULL) -		return sk->sk_prot->compat_getsockopt(sk, level, optname, -						      optval, optlen); -	return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_sock_common_getsockopt); -#endif -  int sock_common_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,  			int flags)  { @@ -3253,7 +3240,7 @@ EXPORT_SYMBOL(sock_common_recvmsg);   *	Set socket options on an inet socket.   */  int sock_common_setsockopt(struct socket *sock, int level, int optname, -			   char __user *optval, unsigned int optlen) +			   sockptr_t optval, unsigned int optlen)  {  	struct sock *sk = sock->sk; @@ -3261,20 +3248,6 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname,  }  EXPORT_SYMBOL(sock_common_setsockopt); -#ifdef CONFIG_COMPAT -int compat_sock_common_setsockopt(struct socket *sock, int level, int optname, -				  char __user *optval, unsigned int optlen) -{ -	struct sock *sk = sock->sk; - -	if (sk->sk_prot->compat_setsockopt != NULL) -		return sk->sk_prot->compat_setsockopt(sk, level, optname, -						      optval, optlen); -	return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_sock_common_setsockopt); -#endif -  void sk_common_release(struct sock *sk)  {  	if (sk->sk_prot->destroy) @@ -3441,6 +3414,16 @@ static void sock_inuse_add(struct net *net, int val)  }  #endif +static void tw_prot_cleanup(struct timewait_sock_ops *twsk_prot) +{ +	if (!twsk_prot) +		return; +	kfree(twsk_prot->twsk_slab_name); +	twsk_prot->twsk_slab_name = NULL; +	kmem_cache_destroy(twsk_prot->twsk_slab); +	twsk_prot->twsk_slab = NULL; +} +  static void req_prot_cleanup(struct request_sock_ops *rsk_prot)  {  	if (!rsk_prot) @@ -3511,7 +3494,7 @@ int proto_register(struct proto *prot, int alloc_slab)  						  prot->slab_flags,  						  NULL);  			if (prot->twsk_prot->twsk_slab == NULL) -				goto out_free_timewait_sock_slab_name; +				goto out_free_timewait_sock_slab;  		}  	} @@ -3519,15 +3502,15 @@ int proto_register(struct proto *prot, int alloc_slab)  	ret = assign_proto_idx(prot);  	if (ret) {  		mutex_unlock(&proto_list_mutex); -		goto out_free_timewait_sock_slab_name; +		goto out_free_timewait_sock_slab;  	}  	list_add(&prot->node, &proto_list);  	mutex_unlock(&proto_list_mutex);  	return ret; -out_free_timewait_sock_slab_name: +out_free_timewait_sock_slab:  	if (alloc_slab && prot->twsk_prot) -		kfree(prot->twsk_prot->twsk_slab_name); +		tw_prot_cleanup(prot->twsk_prot);  out_free_request_sock_slab:  	if (alloc_slab) {  		req_prot_cleanup(prot->rsk_prot); @@ -3551,12 +3534,7 @@ void proto_unregister(struct proto *prot)  	prot->slab = NULL;  	req_prot_cleanup(prot->rsk_prot); - -	if (prot->twsk_prot != NULL && prot->twsk_prot->twsk_slab != NULL) { -		kmem_cache_destroy(prot->twsk_prot->twsk_slab); -		kfree(prot->twsk_prot->twsk_slab_name); -		prot->twsk_prot->twsk_slab = NULL; -	} +	tw_prot_cleanup(prot->twsk_prot);  }  EXPORT_SYMBOL(proto_unregister); @@ -3573,6 +3551,7 @@ int sock_load_diag_module(int family, int protocol)  #ifdef CONFIG_INET  	if (family == AF_INET &&  	    protocol != IPPROTO_RAW && +	    protocol < MAX_INET_PROTOS &&  	    !rcu_access_pointer(inet_protos[protocol]))  		return -ENOENT;  #endif  | 
