net: Fix use after free by removing length arg from sk_data_ready callbacks.
[linux.git] / net / sctp / socket.c
index 981aaf8b6ace45e55b80a235ebbb9dfcb693d64b..e13519e9df80679a618f4e058dce88443b8add6c 100644 (file)
@@ -6593,6 +6593,46 @@ static void __sctp_write_space(struct sctp_association *asoc)
        }
 }
 
+static void sctp_wake_up_waiters(struct sock *sk,
+                                struct sctp_association *asoc)
+{
+       struct sctp_association *tmp = asoc;
+
+       /* We do accounting for the sndbuf space per association,
+        * so we only need to wake our own association.
+        */
+       if (asoc->ep->sndbuf_policy)
+               return __sctp_write_space(asoc);
+
+       /* If association goes down and is just flushing its
+        * outq, then just normally notify others.
+        */
+       if (asoc->base.dead)
+               return sctp_write_space(sk);
+
+       /* Accounting for the sndbuf space is per socket, so we
+        * need to wake up others, try to be fair and in case of
+        * other associations, let them have a go first instead
+        * of just doing a sctp_write_space() call.
+        *
+        * Note that we reach sctp_wake_up_waiters() only when
+        * associations free up queued chunks, thus we are under
+        * lock and the list of associations on a socket is
+        * guaranteed not to change.
+        */
+       for (tmp = list_next_entry(tmp, asocs); 1;
+            tmp = list_next_entry(tmp, asocs)) {
+               /* Manually skip the head element. */
+               if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs))
+                       continue;
+               /* Wake up association. */
+               __sctp_write_space(tmp);
+               /* We've reached the end. */
+               if (tmp == asoc)
+                       break;
+       }
+}
+
 /* Do accounting for the sndbuf space.
  * Decrement the used sndbuf space of the corresponding association by the
  * data size which was just transmitted(freed).
@@ -6620,7 +6660,7 @@ static void sctp_wfree(struct sk_buff *skb)
        sk_mem_uncharge(sk, skb->truesize);
 
        sock_wfree(skb);
-       __sctp_write_space(asoc);
+       sctp_wake_up_waiters(sk, asoc);
 
        sctp_association_put(asoc);
 }
@@ -6705,7 +6745,7 @@ do_nonblock:
        goto out;
 }
 
-void sctp_data_ready(struct sock *sk, int len)
+void sctp_data_ready(struct sock *sk)
 {
        struct socket_wq *wq;