diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 47 | 
1 files changed, 32 insertions, 15 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9e91d6e5df63..981aaf8b6ace 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -64,6 +64,7 @@  #include <linux/crypto.h>  #include <linux/slab.h>  #include <linux/file.h> +#include <linux/compat.h>  #include <net/ip.h>  #include <net/icmp.h> @@ -1368,11 +1369,19 @@ static int sctp_setsockopt_connectx(struct sock *sk,  /*   * New (hopefully final) interface for the API.   * We use the sctp_getaddrs_old structure so that use-space library - * can avoid any unnecessary allocations.   The only defferent part + * can avoid any unnecessary allocations. The only different part   * is that we store the actual length of the address buffer into the - * addrs_num structure member.  That way we can re-use the existing + * addrs_num structure member. That way we can re-use the existing   * code.   */ +#ifdef CONFIG_COMPAT +struct compat_sctp_getaddrs_old { +	sctp_assoc_t	assoc_id; +	s32		addr_num; +	compat_uptr_t	addrs;		/* struct sockaddr * */ +}; +#endif +  static int sctp_getsockopt_connectx3(struct sock *sk, int len,  				     char __user *optval,  				     int __user *optlen) @@ -1381,16 +1390,30 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,  	sctp_assoc_t assoc_id = 0;  	int err = 0; -	if (len < sizeof(param)) -		return -EINVAL; +#ifdef CONFIG_COMPAT +	if (is_compat_task()) { +		struct compat_sctp_getaddrs_old param32; -	if (copy_from_user(¶m, optval, sizeof(param))) -		return -EFAULT; +		if (len < sizeof(param32)) +			return -EINVAL; +		if (copy_from_user(¶m32, optval, sizeof(param32))) +			return -EFAULT; -	err = __sctp_setsockopt_connectx(sk, -			(struct sockaddr __user *)param.addrs, -			param.addr_num, &assoc_id); +		param.assoc_id = param32.assoc_id; +		param.addr_num = param32.addr_num; +		param.addrs = compat_ptr(param32.addrs); +	} else +#endif +	{ +		if (len < sizeof(param)) +			return -EINVAL; +		if (copy_from_user(¶m, optval, sizeof(param))) +			return -EFAULT; +	} +	err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *) +					 param.addrs, param.addr_num, +					 &assoc_id);  	if (err == 0 || err == -EINPROGRESS) {  		if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))  			return -EFAULT; @@ -2092,12 +2115,6 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,  		sctp_skb_pull(skb, copied);  		skb_queue_head(&sk->sk_receive_queue, skb); -		/* When only partial message is copied to the user, increase -		 * rwnd by that amount. If all the data in the skb is read, -		 * rwnd is updated when the event is freed. -		 */ -		if (!sctp_ulpevent_is_notification(event)) -			sctp_assoc_rwnd_increase(event->asoc, copied);  		goto out;  	} else if ((event->msg_flags & MSG_NOTIFICATION) ||  		   (event->msg_flags & MSG_EOR))  | 
