diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2006-01-17 14:51:28 -0500 |
---|---|---|
committer | Sridhar Samudrala <sri@us.ibm.com> | 2006-01-17 14:51:28 -0500 |
commit | 7a48f923b8b27bfaa5f7b2a449a6fe268724ddd5 (patch) | |
tree | 005774759b9f0bba685adc9d9bccbe208a787c2f /net | |
parent | 2664b25051f7ab96b22b199aa2f5ef6a949a4296 (diff) |
[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.c | 29 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 4 |
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) | |||
262 | else | 262 | else |
263 | sctp_backlog_rcv(sk, skb); | 263 | sctp_backlog_rcv(sk, skb); |
264 | 264 | ||
265 | /* Release the sock and any reference counts we took in the | 265 | /* Release the sock and the sock ref we took in the lookup calls. |
266 | * lookup calls. | 266 | * The asoc/ep ref will be released in sctp_backlog_rcv. |
267 | */ | 267 | */ |
268 | sctp_bh_unlock_sock(sk); | 268 | sctp_bh_unlock_sock(sk); |
269 | if (asoc) | ||
270 | sctp_association_put(asoc); | ||
271 | else | ||
272 | sctp_endpoint_put(ep); | ||
273 | sock_put(sk); | 269 | sock_put(sk); |
270 | |||
274 | return ret; | 271 | return ret; |
275 | 272 | ||
276 | discard_it: | 273 | discard_it: |
@@ -296,9 +293,23 @@ discard_release: | |||
296 | int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) | 293 | int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) |
297 | { | 294 | { |
298 | struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; | 295 | struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; |
299 | struct sctp_inq *inqueue = &chunk->rcvr->inqueue; | 296 | struct sctp_inq *inqueue = NULL; |
300 | 297 | struct sctp_ep_common *rcvr = NULL; | |
301 | sctp_inq_push(inqueue, chunk); | 298 | |
299 | rcvr = chunk->rcvr; | ||
300 | if (rcvr->dead) { | ||
301 | sctp_chunk_free(chunk); | ||
302 | } else { | ||
303 | inqueue = &chunk->rcvr->inqueue; | ||
304 | sctp_inq_push(inqueue, chunk); | ||
305 | } | ||
306 | |||
307 | /* Release the asoc/ep ref we took in the lookup calls in sctp_rcv. */ | ||
308 | if (SCTP_EP_TYPE_ASSOCIATION == rcvr->type) | ||
309 | sctp_association_put(sctp_assoc(rcvr)); | ||
310 | else | ||
311 | sctp_endpoint_put(sctp_ep(rcvr)); | ||
312 | |||
302 | return 0; | 313 | return 0; |
303 | } | 314 | } |
304 | 315 | ||
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) | |||
73 | /* If there is a packet which is currently being worked on, | 73 | /* If there is a packet which is currently being worked on, |
74 | * free it as well. | 74 | * free it as well. |
75 | */ | 75 | */ |
76 | if (queue->in_progress) | 76 | if (queue->in_progress) { |
77 | sctp_chunk_free(queue->in_progress); | 77 | sctp_chunk_free(queue->in_progress); |
78 | queue->in_progress = NULL; | ||
79 | } | ||
78 | 80 | ||
79 | if (queue->malloced) { | 81 | if (queue->malloced) { |
80 | /* Dump the master memory segment. */ | 82 | /* Dump the master memory segment. */ |