aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2023-08-23 06:36:15 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2024-01-11 12:47:34 +0000
commitf91f135e15463f0ac094a60e2ca02f1079e64997 (patch)
treed1eb75d7e69fb9feff6a759f2b544ae70a8b57ed
parenteb62bba325f31384a6ae193c655dc1f5ca43f2c7 (diff)
downloadsrc-f91f135e15463f0ac094a60e2ca02f1079e64997.tar.gz
src-f91f135e15463f0ac094a60e2ca02f1079e64997.zip
sctp: improve handling of SHUTDOWN and SHUTDOWN ACK chunks
When handling a SHUTDOWN or SHUTDOWN ACK chunk detect if the peer is violating the protocol by not having made sure all user messages are reveived by the peer. If this situation is detected, abort the association. (cherry picked from commit d18c845f99cbd2d3c0e70b3b9b09d80c655b6fb6)
-rw-r--r--sys/netinet/sctp_input.c54
1 files changed, 42 insertions, 12 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index f93b066f051f..5d2a3dd26384 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -830,6 +830,38 @@ sctp_start_net_timers(struct sctp_tcb *stcb)
}
static void
+sctp_check_data_from_peer(struct sctp_tcb *stcb, int *abort_flag)
+{
+ char msg[SCTP_DIAG_INFO_LEN];
+ struct sctp_association *asoc;
+ struct mbuf *op_err;
+ unsigned int i;
+
+ *abort_flag = 0;
+ asoc = &stcb->asoc;
+ if (SCTP_TSN_GT(asoc->highest_tsn_inside_map, asoc->cumulative_tsn) ||
+ SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->cumulative_tsn)) {
+ SCTP_SNPRINTF(msg, sizeof(msg), "Missing TSN");
+ *abort_flag = 1;
+ }
+ if (!*abort_flag) {
+ for (i = 0; i < asoc->streamincnt; i++) {
+ if (!TAILQ_EMPTY(&asoc->strmin[i].inqueue) ||
+ !TAILQ_EMPTY(&asoc->strmin[i].uno_inqueue)) {
+ SCTP_SNPRINTF(msg, sizeof(msg), "Missing user data");
+ *abort_flag = 1;
+ break;
+ }
+ }
+ }
+ if (*abort_flag) {
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INPUT + SCTP_LOC_9;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
+ }
+}
+
+static void
sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
struct sctp_tcb *stcb, struct sctp_nets *net, int *abort_flag)
{
@@ -852,12 +884,10 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
if (*abort_flag) {
return;
}
- /*
- * FIXME MT: Handle the case where there are still incomplete
- * received user messages or known missing user messages from the
- * peer. One way to handle this is to abort the associations in this
- * case.
- */
+ sctp_check_data_from_peer(stcb, abort_flag);
+ if (*abort_flag) {
+ return;
+ }
if (stcb->sctp_socket) {
if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
(SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT) &&
@@ -914,6 +944,8 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
struct sctp_tcb *stcb,
struct sctp_nets *net)
{
+ int abort_flag;
+
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_shutdown_ack: handling SHUTDOWN ACK\n");
if (stcb == NULL) {
@@ -934,12 +966,10 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
SCTP_TCB_UNLOCK(stcb);
return;
}
- /*
- * FIXME MT: Handle the case where there are still incomplete
- * received user messages or known missing user messages from the
- * peer. One way to handle this is to abort the associations in this
- * case.
- */
+ sctp_check_data_from_peer(stcb, &abort_flag);
+ if (abort_flag) {
+ return;
+ }
#ifdef INVARIANTS
if (!TAILQ_EMPTY(&stcb->asoc.send_queue) ||
!TAILQ_EMPTY(&stcb->asoc.sent_queue) ||