aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorRandall Stewart <rrs@FreeBSD.org>2010-07-03 14:03:31 +0000
committerRandall Stewart <rrs@FreeBSD.org>2010-07-03 14:03:31 +0000
commit478fbccb67af2f618791dcc64bab9840a4e26279 (patch)
tree0b869d1fe192d89568165ce267865d235b145864 /sys
parenta5548bf685205d1f186e3f163b3ee707b621b2b9 (diff)
downloadsrc-478fbccb67af2f618791dcc64bab9840a4e26279.tar.gz
src-478fbccb67af2f618791dcc64bab9840a4e26279.zip
This fixes a crash in SCTP. It was possible to have a
large number of packets queued to a crashing process. In a specific case you may get 2 ABORT's back (from say two packets in flight). If the aborts happened to be processed at the same time its possible to have one free the association while the other is trying to report all the outbound packets. When this occured it could lead to a crash. MFC after: 3 days
Notes
Notes: svn path=/head/; revision=209663
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/sctputil.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 9a8f32f7cf23..e390fb1cde25 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -3694,6 +3694,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
if (stcb == NULL) {
return;
}
+ if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ /* already being freed */
+ return;
+ }
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
@@ -3753,11 +3757,13 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
stcb->asoc.stream_queue_cnt--;
TAILQ_REMOVE(&outs->outqueue, sp, next);
sctp_free_spbufspace(stcb, asoc, sp);
- sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp, so_locked);
if (sp->data) {
- sctp_m_freem(sp->data);
- sp->data = NULL;
+ sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
+ SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp, so_locked);
+ if (sp->data) {
+ sctp_m_freem(sp->data);
+ sp->data = NULL;
+ }
}
if (sp->net)
sctp_free_remote_addr(sp->net);