aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2020-07-23 01:35:24 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2020-07-23 01:35:24 +0000
commit91e04f9e7ab70771497040e53d2ad642a1926311 (patch)
tree5067fc3bcc0aa68a4f2862ddfa1550de15f1fc7c
parente9b21d432bac9f7c95bd282cad6849ce28428aee (diff)
downloadsrc-91e04f9e7ab70771497040e53d2ad642a1926311.tar.gz
src-91e04f9e7ab70771497040e53d2ad642a1926311.zip
Detect and handle an invalid reassembly constellation, which results in
a memory leak. Thanks to Felix Weinrank for finding this issue using fuzz testing the userland stack. MFC after: 1 week
Notes
Notes: svn path=/head/; revision=363440
-rw-r--r--sys/netinet/sctp_constants.h1
-rw-r--r--sys/netinet/sctp_indata.c55
2 files changed, 33 insertions, 23 deletions
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index f042531a7126..158d49a75a6b 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -795,6 +795,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_LOC_34 0x00000022
#define SCTP_LOC_35 0x00000023
#define SCTP_LOC_36 0x00000024
+#define SCTP_LOC_37 0x00000025
/* Free assoc codes */
#define SCTP_NORMAL_PROC 0
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index b34bf6e47f89..9f3bbe8a1b75 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -1567,6 +1567,15 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
chk->rec.data.fsn);
TAILQ_FOREACH(at, &control->reasm, sctp_next) {
if (SCTP_TSN_GT(at->rec.data.fsn, chk->rec.data.fsn)) {
+ if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
+ /* Last not at the end? huh? */
+ SCTPDBG(SCTP_DEBUG_XXX,
+ "Last fragment not last in list: -- abort\n");
+ sctp_abort_in_reasm(stcb, control,
+ chk, abort_flag,
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_14);
+ return;
+ }
/*
* This one in queue is bigger than the new
* one, insert the new one before at.
@@ -1597,7 +1606,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
at->rec.data.fsn);
sctp_abort_in_reasm(stcb, control,
chk, abort_flag,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_14);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_15);
return;
}
}
@@ -1751,7 +1760,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
* Need to send an abort since we had a empty data chunk.
*/
op_err = sctp_generate_no_user_data_cause(tsn);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
@@ -1888,7 +1897,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
SCTP_SNPRINTF(msg, sizeof(msg), "Reassembly problem (MID=%8.8x)", mid);
err_out:
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
@@ -2023,7 +2032,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
(uint16_t)mid);
}
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
@@ -2597,7 +2606,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_18);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_19);
}
sctp_send_shutdown(stcb,
((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination));
@@ -2648,7 +2657,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap)
* there are gaps or duplicates.
*/
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_19);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
}
} else {
@@ -2750,7 +2759,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
SCTP_SNPRINTF(msg, sizeof(msg), "%s", "DATA chunk received when I-DATA was negotiated");
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_20;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21;
sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
return (2);
}
@@ -2761,7 +2770,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-DATA chunk received when DATA was negotiated");
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22;
sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
return (2);
}
@@ -2786,7 +2795,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
ch->chunk_type == SCTP_DATA ? "DATA" : "I-DATA",
chk_length);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23;
sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
return (2);
}
@@ -2874,7 +2883,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
SCTP_SNPRINTF(msg, sizeof(msg), "Chunk of length %u", chk_length);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
return (2);
}
@@ -4025,7 +4034,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
"Cum ack %8.8x greater or equal than TSN %8.8x",
cumack, send_s);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
return;
}
@@ -4201,7 +4210,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
net->dest_state &= ~SCTP_ADDR_PF;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_25);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
/* Done with this net */
@@ -4279,7 +4288,7 @@ again:
} else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_26);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_27);
}
}
}
@@ -4332,7 +4341,7 @@ again:
*abort_now = 1;
/* XXX */
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_27;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
return;
}
@@ -4548,7 +4557,7 @@ hopeless_peer:
"Cum ack %8.8x greater or equal than TSN %8.8x",
cum_ack, send_s);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_28;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_29;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
return;
}
@@ -4580,7 +4589,7 @@ hopeless_peer:
/* stop any timers */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_29);
+ stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
net->partial_bytes_acked = 0;
net->flight_size = 0;
}
@@ -4780,14 +4789,14 @@ hopeless_peer:
if (net->new_pseudo_cumack)
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_30);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_31);
}
} else {
if (accum_moved) {
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
- stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_31);
+ stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
}
}
}
@@ -4950,7 +4959,7 @@ hopeless_peer:
net->dest_state &= ~SCTP_ADDR_PF;
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_33);
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net);
/* Done with this net */
@@ -4975,7 +4984,7 @@ hopeless_peer:
/* stop all timers */
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_33);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_34);
net->flight_size = 0;
net->partial_bytes_acked = 0;
}
@@ -5013,7 +5022,7 @@ hopeless_peer:
*abort_now = 1;
/* XXX */
op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_34;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
return;
}
@@ -5162,7 +5171,7 @@ again:
} else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) {
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_35);
+ SCTP_FROM_SCTP_INDATA + SCTP_LOC_36);
}
}
}
@@ -5565,7 +5574,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
"New cum ack %8.8x too high, highest TSN %8.8x",
new_cum_tsn, asoc->highest_tsn_inside_map);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_36;
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_37;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
return;
}