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

[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
...@@ -262,15 +262,12 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -262,15 +262,12 @@ int sctp_rcv(struct sk_buff *skb)
else else
sctp_backlog_rcv(sk, skb); sctp_backlog_rcv(sk, skb);
/* Release the sock and any reference counts we took in the /* Release the sock and the sock ref we took in the lookup calls.
* lookup calls. * The asoc/ep ref will be released in sctp_backlog_rcv.
*/ */
sctp_bh_unlock_sock(sk); sctp_bh_unlock_sock(sk);
if (asoc)
sctp_association_put(asoc);
else
sctp_endpoint_put(ep);
sock_put(sk); sock_put(sk);
return ret; return ret;
discard_it: discard_it:
...@@ -296,9 +293,23 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -296,9 +293,23 @@ int sctp_rcv(struct sk_buff *skb)
int sctp_backlog_rcv(struct sock *sk, 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_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); 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; return 0;
} }
......
...@@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue) ...@@ -73,8 +73,10 @@ void sctp_inq_free(struct sctp_inq *queue)
/* If there is a packet which is currently being worked on, /* If there is a packet which is currently being worked on,
* free it as well. * free it as well.
*/ */
if (queue->in_progress) if (queue->in_progress) {
sctp_chunk_free(queue->in_progress); sctp_chunk_free(queue->in_progress);
queue->in_progress = NULL;
}
if (queue->malloced) { if (queue->malloced) {
/* Dump the master memory segment. */ /* Dump the master memory segment. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment