diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 112 | 
1 files changed, 77 insertions, 35 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ca44917872d2..fff0926b1111 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -57,6 +57,8 @@   * be incorporated into the next SCTP release.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/types.h>  #include <linux/kernel.h>  #include <linux/wait.h> @@ -109,12 +111,12 @@ static void sctp_sock_migrate(struct sock *, struct sock *,  static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;  extern struct kmem_cache *sctp_bucket_cachep; -extern int sysctl_sctp_mem[3]; +extern long sysctl_sctp_mem[3];  extern int sysctl_sctp_rmem[3];  extern int sysctl_sctp_wmem[3];  static int sctp_memory_pressure; -static atomic_t sctp_memory_allocated; +static atomic_long_t sctp_memory_allocated;  struct percpu_counter sctp_sockets_allocated;  static void sctp_enter_memory_pressure(struct sock *sk) @@ -916,6 +918,11 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,  	/* Walk through the addrs buffer and count the number of addresses. */  	addr_buf = kaddrs;  	while (walk_size < addrs_size) { +		if (walk_size + sizeof(sa_family_t) > addrs_size) { +			kfree(kaddrs); +			return -EINVAL; +		} +  		sa_addr = (struct sockaddr *)addr_buf;  		af = sctp_get_af_specific(sa_addr->sa_family); @@ -1002,9 +1009,13 @@ static int __sctp_connect(struct sock* sk,  	/* Walk through the addrs buffer and count the number of addresses. */  	addr_buf = kaddrs;  	while (walk_size < addrs_size) { +		if (walk_size + sizeof(sa_family_t) > addrs_size) { +			err = -EINVAL; +			goto out_free; +		} +  		sa_addr = (union sctp_addr *)addr_buf;  		af = sctp_get_af_specific(sa_addr->sa.sa_family); -		port = ntohs(sa_addr->v4.sin_port);  		/* If the address family is not supported or if this address  		 * causes the address buffer to overflow return EINVAL. @@ -1014,6 +1025,8 @@ static int __sctp_connect(struct sock* sk,  			goto out_free;  		} +		port = ntohs(sa_addr->v4.sin_port); +  		/* Save current address so we can work with it */  		memcpy(&to, sa_addr, af->sockaddr_len); @@ -2458,9 +2471,8 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,  		if (params.sack_delay == 0 && params.sack_freq == 0)  			return 0;  	} else if (optlen == sizeof(struct sctp_assoc_value)) { -		printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value " -		       "in delayed_ack socket option deprecated\n"); -		printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n"); +		pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n"); +		pr_warn("Use struct sctp_sack_info instead\n");  		if (copy_from_user(¶ms, optval, optlen))  			return -EFAULT; @@ -2868,10 +2880,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned  	int val;  	if (optlen == sizeof(int)) { -		printk(KERN_WARNING -		   "SCTP: Use of int in maxseg socket option deprecated\n"); -		printk(KERN_WARNING -		   "SCTP: Use struct sctp_assoc_value instead\n"); +		pr_warn("Use of int in maxseg socket option deprecated\n"); +		pr_warn("Use struct sctp_assoc_value instead\n");  		if (copy_from_user(&val, optval, optlen))  			return -EFAULT;  		params.assoc_id = 0; @@ -2922,6 +2932,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva  	struct sctp_association	*asoc = NULL;  	struct sctp_setpeerprim	prim;  	struct sctp_chunk	*chunk; +	struct sctp_af		*af;  	int 			err;  	sp = sctp_sk(sk); @@ -2949,6 +2960,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva  	if (!sctp_state(asoc, ESTABLISHED))  		return -ENOTCONN; +	af = sctp_get_af_specific(prim.sspp_addr.ss_family); +	if (!af) +		return -EINVAL; + +	if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL)) +		return -EADDRNOTAVAIL; +  	if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))  		return -EADDRNOTAVAIL; @@ -3121,10 +3139,8 @@ static int sctp_setsockopt_maxburst(struct sock *sk,  	int assoc_id = 0;  	if (optlen == sizeof(int)) { -		printk(KERN_WARNING -		   "SCTP: Use of int in max_burst socket option deprecated\n"); -		printk(KERN_WARNING -		   "SCTP: Use struct sctp_assoc_value instead\n"); +		pr_warn("Use of int in max_burst socket option deprecated\n"); +		pr_warn("Use struct sctp_assoc_value instead\n");  		if (copy_from_user(&val, optval, optlen))  			return -EFAULT;  	} else if (optlen == sizeof(struct sctp_assoc_value)) { @@ -3595,7 +3611,40 @@ out:  /* The SCTP ioctl handler. */  SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)  { -	return -ENOIOCTLCMD; +	int rc = -ENOTCONN; + +	sctp_lock_sock(sk); + +	/* +	 * SEQPACKET-style sockets in LISTENING state are valid, for +	 * SCTP, so only discard TCP-style sockets in LISTENING state. +	 */ +	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) +		goto out; + +	switch (cmd) { +	case SIOCINQ: { +		struct sk_buff *skb; +		unsigned int amount = 0; + +		skb = skb_peek(&sk->sk_receive_queue); +		if (skb != NULL) { +			/* +			 * We will only return the amount of this packet since +			 * that is all that will be read. +			 */ +			amount = skb->len; +		} +		rc = put_user(amount, (int __user *)arg); +		break; +	} +	default: +		rc = -ENOIOCTLCMD; +		break; +	} +out: +	sctp_release_sock(sk); +	return rc;  }  /* This is the function which gets called during socket creation to @@ -3854,7 +3903,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,  	}  out: -	return (retval); +	return retval;  } @@ -3910,7 +3959,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,  	}  out: -	return (retval); +	return retval;  }  /* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) @@ -4281,9 +4330,8 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,  		if (copy_from_user(¶ms, optval, len))  			return -EFAULT;  	} else if (len == sizeof(struct sctp_assoc_value)) { -		printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value " -		       "in delayed_ack socket option deprecated\n"); -		printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n"); +		pr_warn("Use of struct sctp_assoc_value in delayed_ack socket option deprecated\n"); +		pr_warn("Use struct sctp_sack_info instead\n");  		if (copy_from_user(¶ms, optval, len))  			return -EFAULT;  	} else @@ -4929,10 +4977,8 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,  	struct sctp_association *asoc;  	if (len == sizeof(int)) { -		printk(KERN_WARNING -		   "SCTP: Use of int in maxseg socket option deprecated\n"); -		printk(KERN_WARNING -		   "SCTP: Use struct sctp_assoc_value instead\n"); +		pr_warn("Use of int in maxseg socket option deprecated\n"); +		pr_warn("Use struct sctp_assoc_value instead\n");  		params.assoc_id = 0;  	} else if (len >= sizeof(struct sctp_assoc_value)) {  		len = sizeof(struct sctp_assoc_value); @@ -5007,7 +5053,7 @@ static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,  	if (copy_to_user(optval, &val, len))  		return -EFAULT; -	return -ENOTSUPP; +	return 0;  }  /* @@ -5023,10 +5069,8 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,  	struct sctp_association *asoc;  	if (len == sizeof(int)) { -		printk(KERN_WARNING -		   "SCTP: Use of int in max_burst socket option deprecated\n"); -		printk(KERN_WARNING -		   "SCTP: Use struct sctp_assoc_value instead\n"); +		pr_warn("Use of int in max_burst socket option deprecated\n"); +		pr_warn("Use struct sctp_assoc_value instead\n");  		params.assoc_id = 0;  	} else if (len >= sizeof(struct sctp_assoc_value)) {  		len = sizeof(struct sctp_assoc_value); @@ -5569,7 +5613,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)  	/* Note: sk->sk_num gets filled in if ephemeral port request. */  	ret = sctp_get_port_local(sk, &addr); -	return (ret ? 1 : 0); +	return ret ? 1 : 0;  }  /* @@ -5586,8 +5630,7 @@ SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)  		tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);  		if (IS_ERR(tfm)) {  			if (net_ratelimit()) { -				printk(KERN_INFO -				       "SCTP: failed to load transform for %s: %ld\n", +				pr_info("failed to load transform for %s: %ld\n",  					sctp_hmac_alg, PTR_ERR(tfm));  			}  			return -ENOSYS; @@ -5716,13 +5759,12 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)  	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))  		mask |= POLLERR;  	if (sk->sk_shutdown & RCV_SHUTDOWN) -		mask |= POLLRDHUP; +		mask |= POLLRDHUP | POLLIN | POLLRDNORM;  	if (sk->sk_shutdown == SHUTDOWN_MASK)  		mask |= POLLHUP;  	/* Is it readable?  Reconsider this code with TCP-style support.  */ -	if (!skb_queue_empty(&sk->sk_receive_queue) || -	    (sk->sk_shutdown & RCV_SHUTDOWN)) +	if (!skb_queue_empty(&sk->sk_receive_queue))  		mask |= POLLIN | POLLRDNORM;  	/* The association is either gone or not ready.  */  | 
