summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2006-01-17 11:51:28 -0800
committerSridhar Samudrala <sri@us.ibm.com>2006-01-17 11:51:28 -0800
commit7a48f923b8b27bfaa5f7b2a449a6fe268724ddd5 (patch)
tree005774759b9f0bba685adc9d9bccbe208a787c2f /net
parent2664b25051f7ab96b22b199aa2f5ef6a949a4296 (diff)
downloadlinux-7a48f923b8b27bfaa5f7b2a449a6fe268724ddd5.tar.bz2
[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: Sridhar Samudrala <sri@us.ibm.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/input.c29
-rw-r--r--net/sctp/inqueue.c4
2 files changed, 23 insertions, 10 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 4aa6fc60357c..c463e4049c52 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -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;
}
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index 2d33922c044b..297b8951463e 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -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. */