diff options
author | Randall Stewart <rrs@FreeBSD.org> | 2010-07-03 14:03:31 +0000 |
---|---|---|
committer | Randall Stewart <rrs@FreeBSD.org> | 2010-07-03 14:03:31 +0000 |
commit | 478fbccb67af2f618791dcc64bab9840a4e26279 (patch) | |
tree | 0b869d1fe192d89568165ce267865d235b145864 /sys | |
parent | a5548bf685205d1f186e3f163b3ee707b621b2b9 (diff) | |
download | src-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.c | 14 |
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); |