diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 25 | 
1 files changed, 20 insertions, 5 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d37d24ff197..59d16ea927f 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -70,6 +70,7 @@  #include <linux/init.h>  #include <linux/crypto.h>  #include <linux/slab.h> +#include <linux/file.h>  #include <net/ip.h>  #include <net/icmp.h> @@ -4292,6 +4293,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval  {  	sctp_peeloff_arg_t peeloff;  	struct socket *newsock; +	struct file *newfile;  	int retval = 0;  	if (len < sizeof(sctp_peeloff_arg_t)) @@ -4305,22 +4307,35 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval  		goto out;  	/* Map the socket to an unused fd that can be returned to the user.  */ -	retval = sock_map_fd(newsock, 0); +	retval = get_unused_fd();  	if (retval < 0) {  		sock_release(newsock);  		goto out;  	} +	newfile = sock_alloc_file(newsock, 0, NULL); +	if (unlikely(IS_ERR(newfile))) { +		put_unused_fd(retval); +		sock_release(newsock); +		return PTR_ERR(newfile); +	} +  	SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",  			  __func__, sk, newsock->sk, retval);  	/* Return the fd mapped to the new socket.  */ +	if (put_user(len, optlen)) { +		fput(newfile); +		put_unused_fd(retval); +		return -EFAULT; +	}  	peeloff.sd = retval; -	if (put_user(len, optlen)) +	if (copy_to_user(optval, &peeloff, len)) { +		fput(newfile); +		put_unused_fd(retval);  		return -EFAULT; -	if (copy_to_user(optval, &peeloff, len)) -		retval = -EFAULT; - +	} +	fd_install(retval, newfile);  out:  	return retval;  }  |