Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a48f923 authored by Sridhar Samudrala's avatar Sridhar Samudrala
Browse files

[SCTP]: Fix potential race condition between sctp_close() and sctp_rcv().



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: default avatarSridhar Samudrala <sri@us.ibm.com>
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
parent 2664b250
Loading
Loading
Loading
Loading
+20 −9
Original line number Diff line number Diff line
@@ -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 @@ int sctp_rcv(struct sk_buff *skb)
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;
 	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;
}

+3 −1
Original line number Diff line number Diff line
@@ -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.  */