diff options
Diffstat (limited to 'net/socket.c')
| -rw-r--r-- | net/socket.c | 35 | 
1 files changed, 24 insertions, 11 deletions
diff --git a/net/socket.c b/net/socket.c index 682969deaed3..5bc4ee0bb75d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -276,28 +276,41 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *k  static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,  			     void __user *uaddr, int __user *ulen)  { -	int err;  	int len;  	BUG_ON(klen > sizeof(struct sockaddr_storage)); -	err = get_user(len, ulen); -	if (err) -		return err; + +	if (can_do_masked_user_access()) +		ulen = masked_user_access_begin(ulen); +	else if (!user_access_begin(ulen, 4)) +		return -EFAULT; + +	unsafe_get_user(len, ulen, efault_end); +  	if (len > klen)  		len = klen; -	if (len < 0) -		return -EINVAL; +	/* +	 *      "fromlen shall refer to the value before truncation.." +	 *                      1003.1g +	 */ +	if (len >= 0) +		unsafe_put_user(klen, ulen, efault_end); + +	user_access_end(); +  	if (len) { +		if (len < 0) +			return -EINVAL;  		if (audit_sockaddr(klen, kaddr))  			return -ENOMEM;  		if (copy_to_user(uaddr, kaddr, len))  			return -EFAULT;  	} -	/* -	 *      "fromlen shall refer to the value before truncation.." -	 *                      1003.1g -	 */ -	return __put_user(klen, ulen); +	return 0; + +efault_end: +	user_access_end(); +	return -EFAULT;  }  static struct kmem_cache *sock_inode_cachep __ro_after_init;  | 
