diff options
Diffstat (limited to 'net/socket.c')
| -rw-r--r-- | net/socket.c | 191 | 
1 files changed, 94 insertions, 97 deletions
diff --git a/net/socket.c b/net/socket.c index ebed4b68f76..abf56b2a14f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -72,6 +72,7 @@  #include <linux/if_bridge.h>  #include <linux/if_frad.h>  #include <linux/if_vlan.h> +#include <linux/ptp_classify.h>  #include <linux/init.h>  #include <linux/poll.h>  #include <linux/cache.h> @@ -221,12 +222,13 @@ static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,  	int err;  	int len; +	BUG_ON(klen > sizeof(struct sockaddr_storage));  	err = get_user(len, ulen);  	if (err)  		return err;  	if (len > klen)  		len = klen; -	if (len < 0 || len > sizeof(struct sockaddr_storage)) +	if (len < 0)  		return -EINVAL;  	if (len) {  		if (audit_sockaddr(klen, kaddr)) @@ -449,16 +451,17 @@ EXPORT_SYMBOL(sockfd_lookup);  static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)  { -	struct file *file; +	struct fd f = fdget(fd);  	struct socket *sock;  	*err = -EBADF; -	file = fget_light(fd, fput_needed); -	if (file) { -		sock = sock_from_file(file, err); -		if (sock) +	if (f.file) { +		sock = sock_from_file(f.file, err); +		if (likely(sock)) { +			*fput_needed = f.flags;  			return sock; -		fput_light(file, *fput_needed); +		} +		fdput(f);  	}  	return NULL;  } @@ -592,7 +595,7 @@ void sock_release(struct socket *sock)  	}  	if (rcu_dereference_protected(sock->wq, 1)->fasync_list) -		printk(KERN_ERR "sock_release: fasync list not empty!\n"); +		pr_err("%s: fasync list not empty!\n", __func__);  	if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags))  		return; @@ -1264,8 +1267,8 @@ int __sock_create(struct net *net, int family, int type, int protocol,  		static int warned;  		if (!warned) {  			warned = 1; -			printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", -			       current->comm); +			pr_info("%s uses obsolete (PF_INET,SOCK_PACKET)\n", +				current->comm);  		}  		family = PF_PACKET;  	} @@ -1444,48 +1447,61 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,  		err = fd1;  		goto out_release_both;  	} +  	fd2 = get_unused_fd_flags(flags);  	if (unlikely(fd2 < 0)) {  		err = fd2; -		put_unused_fd(fd1); -		goto out_release_both; +		goto out_put_unused_1;  	}  	newfile1 = sock_alloc_file(sock1, flags, NULL);  	if (unlikely(IS_ERR(newfile1))) {  		err = PTR_ERR(newfile1); -		put_unused_fd(fd1); -		put_unused_fd(fd2); -		goto out_release_both; +		goto out_put_unused_both;  	}  	newfile2 = sock_alloc_file(sock2, flags, NULL);  	if (IS_ERR(newfile2)) {  		err = PTR_ERR(newfile2); -		fput(newfile1); -		put_unused_fd(fd1); -		put_unused_fd(fd2); -		sock_release(sock2); -		goto out; +		goto out_fput_1;  	} +	err = put_user(fd1, &usockvec[0]); +	if (err) +		goto out_fput_both; + +	err = put_user(fd2, &usockvec[1]); +	if (err) +		goto out_fput_both; +  	audit_fd_pair(fd1, fd2); +  	fd_install(fd1, newfile1);  	fd_install(fd2, newfile2);  	/* fd1 and fd2 may be already another descriptors.  	 * Not kernel problem.  	 */ -	err = put_user(fd1, &usockvec[0]); -	if (!err) -		err = put_user(fd2, &usockvec[1]); -	if (!err) -		return 0; +	return 0; -	sys_close(fd2); -	sys_close(fd1); -	return err; +out_fput_both: +	fput(newfile2); +	fput(newfile1); +	put_unused_fd(fd2); +	put_unused_fd(fd1); +	goto out; + +out_fput_1: +	fput(newfile1); +	put_unused_fd(fd2); +	put_unused_fd(fd1); +	sock_release(sock2); +	goto out; +out_put_unused_both: +	put_unused_fd(fd2); +out_put_unused_1: +	put_unused_fd(fd1);  out_release_both:  	sock_release(sock2);  out_release_1: @@ -1840,8 +1856,10 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,  	msg.msg_iov = &iov;  	iov.iov_len = size;  	iov.iov_base = ubuf; -	msg.msg_name = (struct sockaddr *)&address; -	msg.msg_namelen = sizeof(address); +	/* Save some cycles and don't copy the address if not needed */ +	msg.msg_name = addr ? (struct sockaddr *)&address : NULL; +	/* We assume all kernel code knows the size of sockaddr_storage */ +	msg.msg_namelen = 0;  	if (sock->file->f_flags & O_NONBLOCK)  		flags |= MSG_DONTWAIT;  	err = sock_recvmsg(sock, &msg, size, flags); @@ -1862,8 +1880,8 @@ out:   *	Receive a datagram from a socket.   */ -asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size, -			 unsigned int flags) +SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size, +		unsigned int, flags)  {  	return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);  } @@ -1964,6 +1982,20 @@ struct used_address {  	unsigned int name_len;  }; +static int copy_msghdr_from_user(struct msghdr *kmsg, +				 struct msghdr __user *umsg) +{ +	if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) +		return -EFAULT; + +	if (kmsg->msg_namelen < 0) +		return -EINVAL; + +	if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) +		kmsg->msg_namelen = sizeof(struct sockaddr_storage); +	return 0; +} +  static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,  			 struct msghdr *msg_sys, unsigned int flags,  			 struct used_address *used_address) @@ -1982,8 +2014,11 @@ static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,  	if (MSG_CMSG_COMPAT & flags) {  		if (get_compat_msghdr(msg_sys, msg_compat))  			return -EFAULT; -	} else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr))) -		return -EFAULT; +	} else { +		err = copy_msghdr_from_user(msg_sys, msg); +		if (err) +			return err; +	}  	if (msg_sys->msg_iovlen > UIO_FASTIOV) {  		err = -EMSGSIZE; @@ -2191,8 +2226,11 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,  	if (MSG_CMSG_COMPAT & flags) {  		if (get_compat_msghdr(msg_sys, msg_compat))  			return -EFAULT; -	} else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr))) -		return -EFAULT; +	} else { +		err = copy_msghdr_from_user(msg_sys, msg); +		if (err) +			return err; +	}  	if (msg_sys->msg_iovlen > UIO_FASTIOV) {  		err = -EMSGSIZE; @@ -2205,16 +2243,14 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,  			goto out;  	} -	/* -	 *      Save the user-mode address (verify_iovec will change the -	 *      kernel msghdr to use the kernel address space) +	/* Save the user-mode address (verify_iovec will change the +	 * kernel msghdr to use the kernel address space)  	 */ -  	uaddr = (__force void __user *)msg_sys->msg_name;  	uaddr_len = COMPAT_NAMELEN(msg); -	if (MSG_CMSG_COMPAT & flags) { +	if (MSG_CMSG_COMPAT & flags)  		err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); -	} else +	else  		err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE);  	if (err < 0)  		goto out_freeiov; @@ -2223,6 +2259,9 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,  	cmsg_ptr = (unsigned long)msg_sys->msg_control;  	msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); +	/* We assume all kernel code knows the size of sockaddr_storage */ +	msg_sys->msg_namelen = 0; +  	if (sock->file->f_flags & O_NONBLOCK)  		flags |= MSG_DONTWAIT;  	err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, @@ -2562,8 +2601,7 @@ int sock_register(const struct net_proto_family *ops)  	int err;  	if (ops->family >= NPROTO) { -		printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, -		       NPROTO); +		pr_crit("protocol %d >= NPROTO(%d)\n", ops->family, NPROTO);  		return -ENOBUFS;  	} @@ -2577,7 +2615,7 @@ int sock_register(const struct net_proto_family *ops)  	}  	spin_unlock(&net_family_lock); -	printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family); +	pr_info("NET: Registered protocol family %d\n", ops->family);  	return err;  }  EXPORT_SYMBOL(sock_register); @@ -2605,7 +2643,7 @@ void sock_unregister(int family)  	synchronize_rcu(); -	printk(KERN_INFO "NET: Unregistered protocol family %d\n", family); +	pr_info("NET: Unregistered protocol family %d\n", family);  }  EXPORT_SYMBOL(sock_unregister); @@ -2648,9 +2686,7 @@ static int __init sock_init(void)  		goto out;  #endif -#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING -	skb_timestamping_init(); -#endif +	ptp_classifier_init();  out:  	return err; @@ -2948,11 +2984,8 @@ static int bond_ioctl(struct net *net, unsigned int cmd,  			 struct compat_ifreq __user *ifr32)  {  	struct ifreq kifr; -	struct ifreq __user *uifr;  	mm_segment_t old_fs;  	int err; -	u32 data; -	void __user *datap;  	switch (cmd) {  	case SIOCBONDENSLAVE: @@ -2969,26 +3002,13 @@ static int bond_ioctl(struct net *net, unsigned int cmd,  		set_fs(old_fs);  		return err; -	case SIOCBONDSLAVEINFOQUERY: -	case SIOCBONDINFOQUERY: -		uifr = compat_alloc_user_space(sizeof(*uifr)); -		if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) -			return -EFAULT; - -		if (get_user(data, &ifr32->ifr_ifru.ifru_data)) -			return -EFAULT; - -		datap = compat_ptr(data); -		if (put_user(datap, &uifr->ifr_ifru.ifru_data)) -			return -EFAULT; - -		return dev_ioctl(net, cmd, uifr);  	default:  		return -ENOIOCTLCMD;  	}  } -static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, +/* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ +static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd,  				 struct compat_ifreq __user *u_ifreq32)  {  	struct ifreq __user *u_ifreq64; @@ -2999,19 +3019,16 @@ static int siocdevprivate_ioctl(struct net *net, unsigned int cmd,  	if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]),  			   IFNAMSIZ))  		return -EFAULT; -	if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) +	if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data))  		return -EFAULT;  	data64 = compat_ptr(data32);  	u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); -	/* Don't check these user accesses, just let that get trapped -	 * in the ioctl handler instead. -	 */  	if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0],  			 IFNAMSIZ))  		return -EFAULT; -	if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) +	if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data))  		return -EFAULT;  	return dev_ioctl(net, cmd, u_ifreq64); @@ -3091,27 +3108,6 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,  	return err;  } -static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) -{ -	void __user *uptr; -	compat_uptr_t uptr32; -	struct ifreq __user *uifr; - -	uifr = compat_alloc_user_space(sizeof(*uifr)); -	if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) -		return -EFAULT; - -	if (get_user(uptr32, &uifr32->ifr_data)) -		return -EFAULT; - -	uptr = compat_ptr(uptr32); - -	if (put_user(uptr, &uifr->ifr_data)) -		return -EFAULT; - -	return dev_ioctl(net, SIOCSHWTSTAMP, uifr); -} -  struct rtentry32 {  	u32		rt_pad1;  	struct sockaddr rt_dst;         /* target address               */ @@ -3223,7 +3219,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,  	struct net *net = sock_net(sk);  	if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) -		return siocdevprivate_ioctl(net, cmd, argp); +		return compat_ifr_data_ioctl(net, cmd, argp);  	switch (cmd) {  	case SIOCSIFBR: @@ -3243,8 +3239,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,  	case SIOCBONDENSLAVE:  	case SIOCBONDRELEASE:  	case SIOCBONDSETHWADDR: -	case SIOCBONDSLAVEINFOQUERY: -	case SIOCBONDINFOQUERY:  	case SIOCBONDCHANGEACTIVE:  		return bond_ioctl(net, cmd, argp);  	case SIOCADDRT: @@ -3254,8 +3248,11 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,  		return do_siocgstamp(net, sock, cmd, argp);  	case SIOCGSTAMPNS:  		return do_siocgstampns(net, sock, cmd, argp); +	case SIOCBONDSLAVEINFOQUERY: +	case SIOCBONDINFOQUERY:  	case SIOCSHWTSTAMP: -		return compat_siocshwtstamp(net, argp); +	case SIOCGHWTSTAMP: +		return compat_ifr_data_ioctl(net, cmd, argp);  	case FIOSETOWN:  	case SIOCSPGRP:  | 
