svn commit: r363440 - head/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Thu Jul 23 01:35:25 UTC 2020
Author: tuexen
Date: Thu Jul 23 01:35:24 2020
New Revision: 363440
URL: https://svnweb.freebsd.org/changeset/base/363440
Log:
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
Modified:
head/sys/netinet/sctp_constants.h
head/sys/netinet/sctp_indata.c
Modified: head/sys/netinet/sctp_constants.h
==============================================================================
--- head/sys/netinet/sctp_constants.h Wed Jul 22 23:39:58 2020 (r363439)
+++ head/sys/netinet/sctp_constants.h Thu Jul 23 01:35:24 2020 (r363440)
@@ -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
Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c Wed Jul 22 23:39:58 2020 (r363439)
+++ head/sys/netinet/sctp_indata.c Thu Jul 23 01:35:24 2020 (r363440)
@@ -1567,6 +1567,15 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struc
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, struc
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, struc
* 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, struc
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, struc
(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 *o
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 *o
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 *o
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 *o
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
"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
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;
}
More information about the svn-src-all
mailing list