]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/sctp/socket.c
[SCTP]: A better solution to fix the race between sctp_peeloff() and
[karo-tx-linux.git] / net / sctp / socket.c
index fc04d185fa3348d8dabc2387f5465b59d3d81b97..b1a17758003a1979d44f4eaee0fc3e71323a7cd8 100644 (file)
@@ -63,6 +63,7 @@
 #include <linux/wait.h>
 #include <linux/time.h>
 #include <linux/ip.h>
+#include <linux/capability.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
 #include <linux/init.h>
@@ -860,7 +861,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
                return -EFAULT;
 
        /* Alloc space for the address array in kernel memory.  */
-       kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL);
+       kaddrs = kmalloc(addrs_size, GFP_KERNEL);
        if (unlikely(!kaddrs))
                return -ENOMEM;
 
@@ -1056,6 +1057,7 @@ static int __sctp_connect(struct sock* sk,
        inet_sk(sk)->dport = htons(asoc->peer.port);
        af = sctp_get_af_specific(to.sa.sa_family);
        af->to_sk_daddr(&to, sk);
+       sk->sk_err = 0;
 
        timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK);
        err = sctp_wait_for_connect(asoc, &timeo);
@@ -1150,7 +1152,7 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
                return -EFAULT;
 
        /* Alloc space for the address array in kernel memory.  */
-       kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL);
+       kaddrs = kmalloc(addrs_size, GFP_KERNEL);
        if (unlikely(!kaddrs))
                return -ENOMEM;
 
@@ -1227,7 +1229,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
 
        ep = sctp_sk(sk)->ep;
 
-       /* Walk all associations on a socket, not on an endpoint.  */
+       /* Walk all associations on an endpoint.  */
        list_for_each_safe(pos, temp, &ep->asocs) {
                asoc = list_entry(pos, struct sctp_association, asocs);
 
@@ -2994,7 +2996,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->hbinterval  = jiffies_to_msecs(sctp_hb_interval);
        sp->pathmaxrxt  = sctp_max_retrans_path;
        sp->pathmtu     = 0; // allow default discovery
-       sp->sackdelay   = sctp_sack_timeout;
+       sp->sackdelay   = jiffies_to_msecs(sctp_sack_timeout);
        sp->param_flags = SPP_HB_ENABLE |
                          SPP_PMTUD_ENABLE |
                          SPP_SACKDELAY_ENABLE;
@@ -4893,6 +4895,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        /* Is there any exceptional events?  */
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
                mask |= POLLHUP;
 
@@ -5314,6 +5318,7 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                 */
                sctp_release_sock(sk);
                current_timeo = schedule_timeout(current_timeo);
+               BUG_ON(sk != asoc->base.sk);
                sctp_lock_sock(sk);
 
                *timeo_p = current_timeo;
@@ -5425,7 +5430,7 @@ out:
        return err;
 
 do_error:
-       if (asoc->init_err_counter + 1 >= asoc->max_init_attempts)
+       if (asoc->init_err_counter + 1 > asoc->max_init_attempts)
                err = -ETIMEDOUT;
        else
                err = -ECONNREFUSED;
@@ -5601,7 +5606,13 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
         */
        newsp->type = type;
 
-       /* Migrate the association to the new socket. */
+       /* Mark the new socket "in-use" by the user so that any packets
+        * that may arrive on the association after we've moved it are
+        * queued to the backlog.  This prevents a potential race between
+        * backlog processing on the old socket and new-packet processing
+        * on the new socket.
+        */
+       sctp_lock_sock(newsk);
        sctp_assoc_migrate(assoc, newsk);
 
        /* If the association on the newsk is already closed before accept()
@@ -5611,6 +5622,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
                newsk->sk_shutdown |= RCV_SHUTDOWN;
 
        newsk->sk_state = SCTP_SS_ESTABLISHED;
+       sctp_release_sock(newsk);
 }
 
 /* This proto struct describes the ULP interface for SCTP.  */