[SCTP]: Fix potential race condition between sctp_close() and sctp_rcv().
authorSridhar Samudrala <sri@us.ibm.com>
Tue, 17 Jan 2006 19:51:28 +0000 (11:51 -0800)
committerSridhar Samudrala <sri@us.ibm.com>
Tue, 17 Jan 2006 19:51:28 +0000 (11:51 -0800)
Do not release the reference to association/endpoint if an incoming skb is
added to backlog. Instead release it after the chunk is processed in
sctp_backlog_rcv().

Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
net/sctp/input.c
net/sctp/inqueue.c

index 4aa6fc6..c463e40 100644 (file)
@@ -262,15 +262,12 @@ int sctp_rcv(struct sk_buff *skb)
        else
                sctp_backlog_rcv(sk, skb);
 
-       /* Release the sock and any reference counts we took in the
-        * lookup calls.
+       /* Release the sock and the sock ref we took in the lookup calls. 
+        * The asoc/ep ref will be released in sctp_backlog_rcv.
         */
        sctp_bh_unlock_sock(sk);
-       if (asoc)
-               sctp_association_put(asoc);
-       else
-               sctp_endpoint_put(ep);
        sock_put(sk);
+
        return ret;
 
 discard_it:
@@ -296,9 +293,23 @@ discard_release:
 int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
-       struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
-
-       sctp_inq_push(inqueue, chunk);
+       struct sctp_inq *inqueue = NULL;
+       struct sctp_ep_common *rcvr = NULL;
+
+       rcvr = chunk->rcvr;
+       if (rcvr->dead) {
+               sctp_chunk_free(chunk);
+       } else {
+               inqueue = &chunk->rcvr->inqueue;
+               sctp_inq_push(inqueue, chunk);
+       }
+
+       /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */ 
+       if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type)
+               sctp_association_put(sctp_assoc(rcvr));
+       else
+               sctp_endpoint_put(sctp_ep(rcvr));
+  
         return 0;
 }
 
index 2d33922..297b895 100644 (file)
@@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue)
        /* If there is a packet which is currently being worked on,
         * free it as well.
         */
-       if (queue->in_progress)
+       if (queue->in_progress) {
                sctp_chunk_free(queue->in_progress);
+               queue->in_progress = NULL;
+       }
 
        if (queue->malloced) {
                /* Dump the master memory segment.  */