* Fix a bug where the length of the ASCONF-ACK was calculated wrong due

to using an uninitialized variable.
* Fix a bug where a NULL pointer was dereferenced when interfaces
  come and go at a high rate.
* Fix a bug where inps where not deregistered from iterators.
* Fix a race condition in freeing an association.
* Fix a refcount problem related to the iterator.
Each of the above bug results in a panic. It shows up when
interfaces come and go at a high rate.

Obtained from: rrs (partly)
MFC after: 3 days
This commit is contained in:
tuexen 2010-06-14 21:25:07 +00:00
parent 7824be8be0
commit 9afd287a77
2 changed files with 20 additions and 13 deletions

View File

@ -826,6 +826,7 @@ send_reply:
ack->serial_number = serial_num; ack->serial_number = serial_num;
ack->last_sent_to = NULL; ack->last_sent_to = NULL;
ack->data = m_ack; ack->data = m_ack;
ack->len = 0;
n = m_ack; n = m_ack;
while (n) { while (n) {
ack->len += SCTP_BUF_LEN(n); ack->len += SCTP_BUF_LEN(n);
@ -1025,7 +1026,8 @@ sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
* address. * address.
*/ */
if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) && if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) &&
SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index) { ((ifn == NULL) ||
(SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) {
/* clear any cached route */ /* clear any cached route */
RTFREE(net->ro.ro_rt); RTFREE(net->ro.ro_rt);
net->ro.ro_rt = NULL; net->ro.ro_rt = NULL;

View File

@ -3074,6 +3074,9 @@ sctp_iterator_inp_being_freed(struct sctp_inpcb *inp)
SCTP_FREE(it, SCTP_M_ITER); SCTP_FREE(it, SCTP_M_ITER);
} else { } else {
it->inp = LIST_NEXT(it->inp, sctp_list); it->inp = LIST_NEXT(it->inp, sctp_list);
if (it->inp) {
SCTP_INP_INCR_REF(it->inp);
}
} }
/* /*
* When its put in the refcnt is incremented so decr * When its put in the refcnt is incremented so decr
@ -3114,17 +3117,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
#ifdef SCTP_LOG_CLOSING #ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 0); sctp_log_closing(inp, NULL, 0);
#endif #endif
if (from == SCTP_CALLED_AFTER_CMPSET_OFCLOSE) { SCTP_ITERATOR_LOCK();
/* /* mark any iterators on the list or being processed */
* Once we are in we can remove the flag from = 1 is only sctp_iterator_inp_being_freed(inp);
* passed from the actual closing routines that are called SCTP_ITERATOR_UNLOCK();
* via the sockets layer.
*/
SCTP_ITERATOR_LOCK();
/* mark any iterators on the list or being processed */
sctp_iterator_inp_being_freed(inp);
SCTP_ITERATOR_UNLOCK();
}
so = inp->sctp_socket; so = inp->sctp_socket;
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
/* been here before.. eeks.. get out of here */ /* been here before.. eeks.. get out of here */
@ -4637,7 +4633,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
atomic_add_int(&stcb->asoc.refcnt, 1); atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb); SCTP_TCB_UNLOCK(stcb);
SCTP_INP_INFO_WLOCK(); SCTP_INP_INFO_WLOCK();
SCTP_INP_WLOCK(inp); SCTP_INP_WLOCK(inp);
SCTP_TCB_LOCK(stcb); SCTP_TCB_LOCK(stcb);
@ -4680,6 +4675,16 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
if (from_inpcbfree == SCTP_NORMAL_PROC) { if (from_inpcbfree == SCTP_NORMAL_PROC) {
atomic_add_int(&stcb->asoc.refcnt, -1); atomic_add_int(&stcb->asoc.refcnt, -1);
} }
if (stcb->asoc.refcnt) {
stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
if (from_inpcbfree == SCTP_NORMAL_PROC) {
SCTP_INP_INFO_WUNLOCK();
SCTP_INP_WUNLOCK(inp);
}
SCTP_TCB_UNLOCK(stcb);
return (0);
}
asoc->state = 0; asoc->state = 0;
if (inp->sctp_tcbhash) { if (inp->sctp_tcbhash) {
LIST_REMOVE(stcb, sctp_tcbhash); LIST_REMOVE(stcb, sctp_tcbhash);