diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 45 | 
1 files changed, 31 insertions, 14 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3204a9b29407..9b01e994f661 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -188,13 +188,13 @@ static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,  		list_for_each_entry(chunk, &t->transmitted, transmitted_list)  			cb(chunk); -	list_for_each_entry(chunk, &q->retransmit, list) +	list_for_each_entry(chunk, &q->retransmit, transmitted_list)  		cb(chunk); -	list_for_each_entry(chunk, &q->sacked, list) +	list_for_each_entry(chunk, &q->sacked, transmitted_list)  		cb(chunk); -	list_for_each_entry(chunk, &q->abandoned, list) +	list_for_each_entry(chunk, &q->abandoned, transmitted_list)  		cb(chunk);  	list_for_each_entry(chunk, &q->out_chunk_list, list) @@ -2277,7 +2277,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,  		if (asoc && sctp_outq_is_empty(&asoc->outqueue)) {  			event = sctp_ulpevent_make_sender_dry_event(asoc, -					GFP_ATOMIC); +					GFP_USER | __GFP_NOWARN);  			if (!event)  				return -ENOMEM; @@ -3498,6 +3498,8 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,  	if (optlen < sizeof(struct sctp_hmacalgo))  		return -EINVAL; +	optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) + +					     SCTP_AUTH_NUM_HMACS * sizeof(u16));  	hmacs = memdup_user(optval, optlen);  	if (IS_ERR(hmacs)) @@ -3536,6 +3538,11 @@ static int sctp_setsockopt_auth_key(struct sock *sk,  	if (optlen <= sizeof(struct sctp_authkey))  		return -EINVAL; +	/* authkey->sca_keylength is u16, so optlen can't be bigger than +	 * this. +	 */ +	optlen = min_t(unsigned int, optlen, USHRT_MAX + +					     sizeof(struct sctp_authkey));  	authkey = memdup_user(optval, optlen);  	if (IS_ERR(authkey)) @@ -3891,13 +3898,20 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,  	struct sctp_association *asoc;  	int retval = -EINVAL; -	if (optlen < sizeof(struct sctp_reset_streams)) +	if (optlen < sizeof(*params))  		return -EINVAL; +	/* srs_number_streams is u16, so optlen can't be bigger than this. */ +	optlen = min_t(unsigned int, optlen, USHRT_MAX + +					     sizeof(__u16) * sizeof(*params));  	params = memdup_user(optval, optlen);  	if (IS_ERR(params))  		return PTR_ERR(params); +	if (params->srs_number_streams * sizeof(__u16) > +	    optlen - sizeof(*params)) +		goto out; +  	asoc = sctp_id2assoc(sk, params->srs_assoc_id);  	if (!asoc)  		goto out; @@ -4494,7 +4508,7 @@ static int sctp_init_sock(struct sock *sk)  	SCTP_DBG_OBJCNT_INC(sock);  	local_bh_disable(); -	percpu_counter_inc(&sctp_sockets_allocated); +	sk_sockets_allocated_inc(sk);  	sock_prot_inuse_add(net, sk->sk_prot, 1);  	/* Nothing can fail after this block, otherwise @@ -4538,7 +4552,7 @@ static void sctp_destroy_sock(struct sock *sk)  	}  	sctp_endpoint_free(sp->ep);  	local_bh_disable(); -	percpu_counter_dec(&sctp_sockets_allocated); +	sk_sockets_allocated_dec(sk);  	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);  	local_bh_enable();  } @@ -5011,7 +5025,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv  	len = sizeof(int);  	if (put_user(len, optlen))  		return -EFAULT; -	if (copy_to_user(optval, &sctp_sk(sk)->autoclose, sizeof(int))) +	if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len))  		return -EFAULT;  	return 0;  } @@ -5080,7 +5094,6 @@ static int sctp_getsockopt_peeloff_common(struct sock *sk, sctp_peeloff_arg_t *p  	*newfile = sock_alloc_file(newsock, 0, NULL);  	if (IS_ERR(*newfile)) {  		put_unused_fd(retval); -		sock_release(newsock);  		retval = PTR_ERR(*newfile);  		*newfile = NULL;  		return retval; @@ -5642,6 +5655,9 @@ copy_getaddrs:  		err = -EFAULT;  		goto out;  	} +	/* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too, +	 * but we can't change it anymore. +	 */  	if (put_user(bytes_copied, optlen))  		err = -EFAULT;  out: @@ -6078,7 +6094,7 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,  		params.assoc_id = 0;  	} else if (len >= sizeof(struct sctp_assoc_value)) {  		len = sizeof(struct sctp_assoc_value); -		if (copy_from_user(¶ms, optval, sizeof(params))) +		if (copy_from_user(¶ms, optval, len))  			return -EFAULT;  	} else  		return -EINVAL; @@ -6248,7 +6264,9 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,  	if (len < sizeof(struct sctp_authkeyid))  		return -EINVAL; -	if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) + +	len = sizeof(struct sctp_authkeyid); +	if (copy_from_user(&val, optval, len))  		return -EFAULT;  	asoc = sctp_id2assoc(sk, val.scact_assoc_id); @@ -6260,7 +6278,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,  	else  		val.scact_keynumber = ep->active_key_id; -	len = sizeof(struct sctp_authkeyid);  	if (put_user(len, optlen))  		return -EFAULT;  	if (copy_to_user(optval, &val, len)) @@ -6286,7 +6303,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,  	if (len < sizeof(struct sctp_authchunks))  		return -EINVAL; -	if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) +	if (copy_from_user(&val, optval, sizeof(val)))  		return -EFAULT;  	to = p->gauth_chunks; @@ -6331,7 +6348,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,  	if (len < sizeof(struct sctp_authchunks))  		return -EINVAL; -	if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) +	if (copy_from_user(&val, optval, sizeof(val)))  		return -EFAULT;  	to = p->gauth_chunks;  | 
