sctp: improve error handling in INIT/INIT-ACK processing

When processing INIT and INIT-ACK information, also during
COOKIE processing, delete the current association, when it
would end up in an inconsistent state.

MFC after:	3 days
This commit is contained in:
Michael Tuexen 2021-05-02 22:38:27 +02:00
parent 4f592683c3
commit 5f2e183505

View file

@ -449,18 +449,24 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
asoc = &stcb->asoc;
asoc->peer_supports_nat = (uint8_t)nat_friendly;
/* process the peer's parameters in the INIT-ACK */
retval = sctp_process_init((struct sctp_init_chunk *)cp, stcb);
if (retval < 0) {
if (sctp_process_init((struct sctp_init_chunk *)cp, stcb) < 0) {
if (op_err != NULL) {
sctp_m_freem(op_err);
}
return (retval);
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, net->port);
*abort_no_unlock = 1;
return (-1);
}
initack_limit = offset + ntohs(cp->ch.chunk_length);
/* load all addresses */
if ((retval = sctp_load_addresses_from_init(stcb, m,
(offset + sizeof(struct sctp_init_chunk)), initack_limit,
src, dst, NULL, stcb->asoc.port))) {
offset + sizeof(struct sctp_init_chunk),
initack_limit, src, dst, NULL, stcb->asoc.port)) < 0) {
if (op_err != NULL) {
sctp_m_freem(op_err);
}
@ -1458,10 +1464,15 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* the right seq no's.
*/
/* First we must process the INIT !! */
retval = sctp_process_init(init_cp, stcb);
if (retval < 0) {
if (sctp_process_init(init_cp, stcb) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 3;
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, net->port);
return (NULL);
}
/* we have already processed the INIT so no problem */
@ -1523,16 +1534,20 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
break;
} /* end switch */
sctp_stop_all_cookie_timers(stcb);
/*
* We ignore the return code here.. not sure if we should
* somehow abort.. but we do have an existing asoc. This
* really should not fail.
*/
if (sctp_load_addresses_from_init(stcb, m,
if ((ret = sctp_load_addresses_from_init(stcb, m,
init_offset + sizeof(struct sctp_init_chunk),
initack_offset, src, dst, init_src, stcb->asoc.port)) {
initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 4;
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Problem with address parameters");
SCTPDBG(SCTP_DEBUG_INPUT1,
"Load addresses from INIT causes an abort %d\n",
retval);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, net->port);
return (NULL);
}
/* respond with a COOKIE-ACK */
@ -1650,17 +1665,31 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
}
}
/* process the INIT info (peer's info) */
retval = sctp_process_init(init_cp, stcb);
if (retval < 0) {
if (sctp_process_init(init_cp, stcb) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 9;
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, net->port);
return (NULL);
}
if (sctp_load_addresses_from_init(stcb, m,
if ((retval = sctp_load_addresses_from_init(stcb, m,
init_offset + sizeof(struct sctp_init_chunk),
initack_offset, src, dst, init_src, stcb->asoc.port)) {
initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 10;
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Problem with address parameters");
SCTPDBG(SCTP_DEBUG_INPUT1,
"Load addresses from INIT causes an abort %d\n",
retval);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, net->port);
return (NULL);
}
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
@ -1874,11 +1903,15 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
asoc->total_flight = 0;
asoc->total_flight_count = 0;
/* process the INIT info (peer's info) */
retval = sctp_process_init(init_cp, stcb);
if (retval < 0) {
if (sctp_process_init(init_cp, stcb) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 13;
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, net->port);
return (NULL);
}
/*
@ -1887,12 +1920,20 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/
net->hb_responded = 1;
if (sctp_load_addresses_from_init(stcb, m,
if ((retval = sctp_load_addresses_from_init(stcb, m,
init_offset + sizeof(struct sctp_init_chunk),
initack_offset, src, dst, init_src, stcb->asoc.port)) {
initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 14;
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Problem with address parameters");
SCTPDBG(SCTP_DEBUG_INPUT1,
"Load addresses from INIT causes an abort %d\n",
retval);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, net->port);
return (NULL);
}
/* respond with a COOKIE-ACK */
@ -2047,16 +2088,15 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
/* process the INIT info (peer's info) */
retval = sctp_process_init(init_cp, stcb);
if (retval < 0) {
if (sctp_process_init(init_cp, stcb) < 0) {
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_19);
return (NULL);
}
/* load all addresses */
if (sctp_load_addresses_from_init(stcb, m,
init_offset + sizeof(struct sctp_init_chunk), initack_offset,
src, dst, init_src, port)) {
if ((retval = sctp_load_addresses_from_init(stcb, m,
init_offset + sizeof(struct sctp_init_chunk),
initack_offset, src, dst, init_src, port)) < 0) {
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_20);
return (NULL);
@ -2518,6 +2558,9 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
&notification, auth_skipped, auth_offset, auth_len,
mflowtype, mflowid,
vrf_id, port);
if (*stcb == NULL) {
*locked_tcb = NULL;
}
}
if (*stcb == NULL) {