Author: tuexen
Date: Mon Aug 24 09:14:32 2020
New Revision: 364642
URL: https://svnweb.freebsd.org/changeset/base/364642

Log:
  MFC r363440:
  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.

Modified:
  stable/12/sys/netinet/sctp_constants.h
  stable/12/sys/netinet/sctp_indata.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/netinet/sctp_constants.h
==============================================================================
--- stable/12/sys/netinet/sctp_constants.h      Mon Aug 24 09:13:06 2020        
(r364641)
+++ stable/12/sys/netinet/sctp_constants.h      Mon Aug 24 09:14:32 2020        
(r364642)
@@ -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: stable/12/sys/netinet/sctp_indata.c
==============================================================================
--- stable/12/sys/netinet/sctp_indata.c Mon Aug 24 09:13:06 2020        
(r364641)
+++ stable/12/sys/netinet/sctp_indata.c Mon Aug 24 09:14:32 2020        
(r364642)
@@ -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;
                }
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to