Improve the error handling in generating ASCONF chunks.
In case of errors, the cleanup was not consistent. Thanks to Felix Weinrank for fuzzing the userland stack and making me aware of the issue. MFC after: 1 week
This commit is contained in:
parent
aeafed21c4
commit
504ee6a001
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=363194
@ -2587,14 +2587,14 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
|
|||||||
if (m_asconf_chk == NULL) {
|
if (m_asconf_chk == NULL) {
|
||||||
/* no mbuf's */
|
/* no mbuf's */
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||||
"compose_asconf: couldn't get chunk mbuf!\n");
|
"sctp_compose_asconf: couldn't get chunk mbuf!\n");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
|
m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
|
||||||
if (m_asconf == NULL) {
|
if (m_asconf == NULL) {
|
||||||
/* no mbuf's */
|
/* no mbuf's */
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||||
"compose_asconf: couldn't get mbuf!\n");
|
"sctp_compose_asconf: couldn't get mbuf!\n");
|
||||||
sctp_m_freem(m_asconf_chk);
|
sctp_m_freem(m_asconf_chk);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
@ -2719,10 +2719,12 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
p_size = 0;
|
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||||
addr_size = 0;
|
"sctp_compose_asconf: no usable lookup addr (family = %d)!\n",
|
||||||
addr_ptr = NULL;
|
found_addr->sa_family);
|
||||||
break;
|
sctp_m_freem(m_asconf_chk);
|
||||||
|
sctp_m_freem(m_asconf);
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
|
lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
|
||||||
memcpy(lookup->addr, addr_ptr, addr_size);
|
memcpy(lookup->addr, addr_ptr, addr_size);
|
||||||
@ -2730,12 +2732,10 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
|
|||||||
} else {
|
} else {
|
||||||
/* uh oh... don't have any address?? */
|
/* uh oh... don't have any address?? */
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||||
"compose_asconf: no lookup addr!\n");
|
"sctp_compose_asconf: no lookup addr!\n");
|
||||||
/* XXX for now, we send a IPv4 address of 0.0.0.0 */
|
sctp_m_freem(m_asconf_chk);
|
||||||
lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS);
|
sctp_m_freem(m_asconf);
|
||||||
lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)));
|
return (NULL);
|
||||||
memset(lookup->addr, 0, sizeof(struct in_addr));
|
|
||||||
SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* chain it all together */
|
/* chain it all together */
|
||||||
@ -3261,10 +3261,9 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
|
sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||||
struct sctp_nets *net)
|
|
||||||
{
|
{
|
||||||
struct sctp_asconf_addr *aa;
|
struct sctp_asconf_addr *aa_vtag, *aa_add, *aa_del;
|
||||||
struct sctp_ifa *sctp_ifap;
|
struct sctp_ifa *sctp_ifap;
|
||||||
struct sctp_asconf_tag_param *vtag;
|
struct sctp_asconf_tag_param *vtag;
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
@ -3273,6 +3272,7 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
|
|||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
struct sockaddr_in6 *to6;
|
struct sockaddr_in6 *to6;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (net == NULL) {
|
if (net == NULL) {
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
|
SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
|
||||||
return;
|
return;
|
||||||
@ -3282,105 +3282,81 @@ sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Need to have in the asconf: - vtagparam(my_vtag/peer_vtag) -
|
* Need to have in the ASCONF: - VTAG(my_vtag/peer_vtag) -
|
||||||
* add(0.0.0.0) - del(0.0.0.0) - Any global addresses add(addr)
|
* ADD(wildcard) - DEL(wildcard) - ADD(Any global addresses)
|
||||||
*/
|
*/
|
||||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
SCTP_MALLOC(aa_vtag, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
|
||||||
SCTP_M_ASC_ADDR);
|
SCTP_MALLOC(aa_add, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
|
||||||
if (aa == NULL) {
|
SCTP_MALLOC(aa_del, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
|
||||||
/* didn't get memory */
|
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
if ((aa_vtag == NULL) || (aa_add == NULL) || (aa_del == NULL)) {
|
||||||
"sctp_asconf_send_nat_state_update: failed to get memory!\n");
|
/* Didn't get memory */
|
||||||
|
SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: failed to get memory!\n");
|
||||||
|
out:
|
||||||
|
if (aa_vtag != NULL) {
|
||||||
|
SCTP_FREE(aa_vtag, SCTP_M_ASC_ADDR);
|
||||||
|
}
|
||||||
|
if (aa_add != NULL) {
|
||||||
|
SCTP_FREE(aa_add, SCTP_M_ASC_ADDR);
|
||||||
|
}
|
||||||
|
if (aa_del != NULL) {
|
||||||
|
SCTP_FREE(aa_del, SCTP_M_ASC_ADDR);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aa->special_del = 0;
|
memset(aa_vtag, 0, sizeof(struct sctp_asconf_addr));
|
||||||
/* fill in asconf address parameter fields */
|
aa_vtag->special_del = 0;
|
||||||
/* top level elements are "networked" during send */
|
/* Fill in ASCONF address parameter fields. */
|
||||||
aa->ifa = NULL;
|
/* Top level elements are "networked" during send. */
|
||||||
aa->sent = 0; /* clear sent flag */
|
aa_vtag->ifa = NULL;
|
||||||
vtag = (struct sctp_asconf_tag_param *)&aa->ap.aph;
|
aa_vtag->sent = 0; /* clear sent flag */
|
||||||
|
vtag = (struct sctp_asconf_tag_param *)&aa_vtag->ap.aph;
|
||||||
vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
|
vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
|
||||||
vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
|
vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
|
||||||
vtag->local_vtag = htonl(stcb->asoc.my_vtag);
|
vtag->local_vtag = htonl(stcb->asoc.my_vtag);
|
||||||
vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
|
vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
|
||||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
|
||||||
|
|
||||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
memset(aa_add, 0, sizeof(struct sctp_asconf_addr));
|
||||||
SCTP_M_ASC_ADDR);
|
memset(aa_del, 0, sizeof(struct sctp_asconf_addr));
|
||||||
if (aa == NULL) {
|
|
||||||
/* didn't get memory */
|
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
|
||||||
"sctp_asconf_send_nat_state_update: failed to get memory!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memset(aa, 0, sizeof(struct sctp_asconf_addr));
|
|
||||||
/* fill in asconf address parameter fields */
|
|
||||||
/* ADD(0.0.0.0) */
|
|
||||||
switch (net->ro._l_addr.sa.sa_family) {
|
switch (net->ro._l_addr.sa.sa_family) {
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
||||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
|
aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
|
||||||
aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
|
aa_add->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
|
||||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
|
aa_add->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
|
||||||
/* No need to add an address, we are using 0.0.0.0 */
|
/* No need to fill the address, we are using 0.0.0.0 */
|
||||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
aa_del->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
||||||
|
aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
|
||||||
|
aa_del->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
|
||||||
|
aa_del->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
|
||||||
|
/* No need to fill the address, we are using 0.0.0.0 */
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
||||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
|
aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
|
||||||
aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
|
aa_add->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
|
||||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
|
aa_add->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
|
||||||
/* No need to add an address, we are using 0.0.0.0 */
|
/* No need to fill the address, we are using ::0 */
|
||||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
aa_del->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
|
||||||
|
aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
|
||||||
|
aa_del->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
|
||||||
|
aa_del->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
|
||||||
|
/* No need to fill the address, we are using ::0 */
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||||
"sctp_asconf_send_nat_state_update: unknown address family\n");
|
"sctp_asconf_send_nat_state_update: unknown address family %d\n",
|
||||||
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
|
net->ro._l_addr.sa.sa_family);
|
||||||
return;
|
goto out;
|
||||||
}
|
|
||||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
|
||||||
SCTP_M_ASC_ADDR);
|
|
||||||
if (aa == NULL) {
|
|
||||||
/* didn't get memory */
|
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
|
||||||
"sctp_asconf_send_nat_state_update: failed to get memory!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memset(aa, 0, sizeof(struct sctp_asconf_addr));
|
|
||||||
/* fill in asconf address parameter fields */
|
|
||||||
/* ADD(0.0.0.0) */
|
|
||||||
switch (net->ro._l_addr.sa.sa_family) {
|
|
||||||
#ifdef INET
|
|
||||||
case AF_INET:
|
|
||||||
aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
|
|
||||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
|
|
||||||
aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
|
|
||||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
|
|
||||||
/* No need to add an address, we are using 0.0.0.0 */
|
|
||||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef INET6
|
|
||||||
case AF_INET6:
|
|
||||||
aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
|
|
||||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
|
|
||||||
aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
|
|
||||||
aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
|
|
||||||
/* No need to add an address, we are using 0.0.0.0 */
|
|
||||||
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
|
||||||
"sctp_asconf_send_nat_state_update: unknown address family\n");
|
|
||||||
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_vtag, next);
|
||||||
|
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_add, next);
|
||||||
|
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_del, next);
|
||||||
|
|
||||||
/* Now we must hunt the addresses and add all global addresses */
|
/* Now we must hunt the addresses and add all global addresses */
|
||||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
||||||
struct sctp_vrf *vrf = NULL;
|
struct sctp_vrf *vrf = NULL;
|
||||||
|
@ -800,13 +800,13 @@ sctp_handle_abort(struct sctp_abort_chunk *abort,
|
|||||||
cause = (struct sctp_error_cause *)(abort + 1);
|
cause = (struct sctp_error_cause *)(abort + 1);
|
||||||
error = ntohs(cause->code);
|
error = ntohs(cause->code);
|
||||||
if (error == SCTP_CAUSE_NAT_COLLIDING_STATE) {
|
if (error == SCTP_CAUSE_NAT_COLLIDING_STATE) {
|
||||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n",
|
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state, ABORT flags:%x\n",
|
||||||
abort->ch.chunk_flags);
|
abort->ch.chunk_flags);
|
||||||
if (sctp_handle_nat_colliding_state(stcb)) {
|
if (sctp_handle_nat_colliding_state(stcb)) {
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
} else if (error == SCTP_CAUSE_NAT_MISSING_STATE) {
|
} else if (error == SCTP_CAUSE_NAT_MISSING_STATE) {
|
||||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags:%x\n",
|
SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state, ABORT flags:%x\n",
|
||||||
abort->ch.chunk_flags);
|
abort->ch.chunk_flags);
|
||||||
if (sctp_handle_nat_missing_state(stcb, net)) {
|
if (sctp_handle_nat_missing_state(stcb, net)) {
|
||||||
return (0);
|
return (0);
|
||||||
@ -1146,14 +1146,14 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
|
|||||||
cause_code);
|
cause_code);
|
||||||
break;
|
break;
|
||||||
case SCTP_CAUSE_NAT_COLLIDING_STATE:
|
case SCTP_CAUSE_NAT_COLLIDING_STATE:
|
||||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags: %x\n",
|
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state, ERROR flags: %x\n",
|
||||||
ch->chunk_flags);
|
ch->chunk_flags);
|
||||||
if (sctp_handle_nat_colliding_state(stcb)) {
|
if (sctp_handle_nat_colliding_state(stcb)) {
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SCTP_CAUSE_NAT_MISSING_STATE:
|
case SCTP_CAUSE_NAT_MISSING_STATE:
|
||||||
SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state abort flags: %x\n",
|
SCTPDBG(SCTP_DEBUG_INPUT2, "Received missing state, ERROR flags: %x\n",
|
||||||
ch->chunk_flags);
|
ch->chunk_flags);
|
||||||
if (sctp_handle_nat_missing_state(stcb, net)) {
|
if (sctp_handle_nat_missing_state(stcb, net)) {
|
||||||
return (0);
|
return (0);
|
||||||
|
Loading…
Reference in New Issue
Block a user