Author: tuexen
Date: Sun May 26 16:43:06 2019
New Revision: 348289
URL: https://svnweb.freebsd.org/changeset/base/348289

Log:
  MFC r347975:
  Improve input validation for the IPPROTO_SCTP level socket options
  SCTP_CONNECT_X and SCTP_CONNECT_X_DELAYED.
  
  MFC r347976:
  Allow sending on demand SCTP HEARTBEATS only in the ESTABLISHED state.
  This issue was found by running syzkaller.

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

Modified: stable/12/sys/netinet/sctp_usrreq.c
==============================================================================
--- stable/12/sys/netinet/sctp_usrreq.c Sun May 26 15:44:58 2019        
(r348288)
+++ stable/12/sys/netinet/sctp_usrreq.c Sun May 26 16:43:06 2019        
(r348289)
@@ -1352,13 +1352,12 @@ static int
 sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
     size_t optsize, void *p, int delay)
 {
-       int error = 0;
+       int error;
        int creat_lock_on = 0;
        struct sctp_tcb *stcb = NULL;
        struct sockaddr *sa;
        unsigned int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
        uint32_t vrf_id;
-       int bad_addresses = 0;
        sctp_assoc_t *a_id;
 
        SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
@@ -1397,17 +1396,12 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb
        totaddrp = (unsigned int *)optval;
        totaddr = *totaddrp;
        sa = (struct sockaddr *)(totaddrp + 1);
-       stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, 
&error, (unsigned int)(optsize - sizeof(int)), &bad_addresses);
-       if ((stcb != NULL) || bad_addresses) {
+       error = sctp_connectx_helper_find(inp, sa, totaddr, &num_v4, &num_v6, 
(unsigned int)(optsize - sizeof(int)));
+       if (error != 0) {
                /* Already have or am bring up an association */
                SCTP_ASOC_CREATE_UNLOCK(inp);
                creat_lock_on = 0;
-               if (stcb)
-                       SCTP_TCB_UNLOCK(stcb);
-               if (bad_addresses == 0) {
-                       SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 
SCTP_FROM_SCTP_USRREQ, EALREADY);
-                       error = EALREADY;
-               }
+               SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, 
error);
                goto out_now;
        }
 #ifdef INET6
@@ -5338,10 +5332,11 @@ sctp_setopt(struct socket *so, int optname, void *optv
                                                net->dest_state &= 
~SCTP_ADDR_NOHB;
                                        }
                                        if (paddrp->spp_flags & SPP_HB_DEMAND) {
-                                               /* on demand HB */
-                                               sctp_send_hb(stcb, net, 
SCTP_SO_LOCKED);
-                                               sctp_chunk_output(inp, stcb, 
SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
-                                               
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
+                                               if (SCTP_GET_STATE(stcb) == 
SCTP_STATE_OPEN) {
+                                                       sctp_send_hb(stcb, net, 
SCTP_SO_LOCKED);
+                                                       sctp_chunk_output(inp, 
stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
+                                                       
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
+                                               }
                                        }
                                        if ((paddrp->spp_flags & 
SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
                                                if 
(SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {

Modified: stable/12/sys/netinet/sctputil.c
==============================================================================
--- stable/12/sys/netinet/sctputil.c    Sun May 26 15:44:58 2019        
(r348288)
+++ stable/12/sys/netinet/sctputil.c    Sun May 26 16:43:06 2019        
(r348289)
@@ -6391,30 +6391,33 @@ out_now:
        return (added);
 }
 
-struct sctp_tcb *
+int
 sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
-    unsigned int *totaddr,
-    unsigned int *num_v4, unsigned int *num_v6, int *error,
-    unsigned int limit, int *bad_addr)
+    unsigned int totaddr,
+    unsigned int *num_v4, unsigned int *num_v6,
+    unsigned int limit)
 {
        struct sockaddr *sa;
-       struct sctp_tcb *stcb = NULL;
+       struct sctp_tcb *stcb;
        unsigned int incr, at, i;
 
        at = 0;
        sa = addr;
-       *error = *num_v6 = *num_v4 = 0;
+       *num_v6 = *num_v4 = 0;
        /* account and validate addresses */
-       for (i = 0; i < *totaddr; i++) {
+       if (totaddr == 0) {
+               return (EINVAL);
+       }
+       for (i = 0; i < totaddr; i++) {
+               if (at + sizeof(struct sockaddr) > limit) {
+                       return (EINVAL);
+               }
                switch (sa->sa_family) {
 #ifdef INET
                case AF_INET:
                        incr = (unsigned int)sizeof(struct sockaddr_in);
                        if (sa->sa_len != incr) {
-                               SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 
SCTP_FROM_SCTPUTIL, EINVAL);
-                               *error = EINVAL;
-                               *bad_addr = 1;
-                               return (NULL);
+                               return (EINVAL);
                        }
                        (*num_v4) += 1;
                        break;
@@ -6427,46 +6430,34 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, stru
                                sin6 = (struct sockaddr_in6 *)sa;
                                if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
                                        /* Must be non-mapped for connectx */
-                                       SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 
SCTP_FROM_SCTPUTIL, EINVAL);
-                                       *error = EINVAL;
-                                       *bad_addr = 1;
-                                       return (NULL);
+                                       return (EINVAL);
                                }
                                incr = (unsigned int)sizeof(struct 
sockaddr_in6);
                                if (sa->sa_len != incr) {
-                                       SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 
SCTP_FROM_SCTPUTIL, EINVAL);
-                                       *error = EINVAL;
-                                       *bad_addr = 1;
-                                       return (NULL);
+                                       return (EINVAL);
                                }
                                (*num_v6) += 1;
                                break;
                        }
 #endif
                default:
-                       *totaddr = i;
-                       incr = 0;
-                       /* we are done */
-                       break;
+                       return (EINVAL);
                }
-               if (i == *totaddr) {
-                       break;
+               if ((at + incr) > limit) {
+                       return (EINVAL);
                }
                SCTP_INP_INCR_REF(inp);
                stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
                if (stcb != NULL) {
-                       /* Already have or am bring up an association */
-                       return (stcb);
+                       SCTP_TCB_UNLOCK(stcb);
+                       return (EALREADY);
                } else {
                        SCTP_INP_DECR_REF(inp);
                }
-               if ((at + incr) > limit) {
-                       *totaddr = i;
-                       break;
-               }
+               at += incr;
                sa = (struct sockaddr *)((caddr_t)sa + incr);
        }
-       return ((struct sctp_tcb *)NULL);
+       return (0);
 }
 
 /*

Modified: stable/12/sys/netinet/sctputil.h
==============================================================================
--- stable/12/sys/netinet/sctputil.h    Sun May 26 15:44:58 2019        
(r348288)
+++ stable/12/sys/netinet/sctputil.h    Sun May 26 16:43:06 2019        
(r348289)
@@ -211,10 +211,9 @@ int
 sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
     int totaddr, int *error);
 
-struct sctp_tcb *
-sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
-    unsigned int *totaddr, unsigned int *num_v4, unsigned int *num_v6,
-    int *error, unsigned int limit, int *bad_addr);
+int
+sctp_connectx_helper_find(struct sctp_inpcb *, struct sockaddr *,
+    unsigned int, unsigned int *, unsigned int *, unsigned int);
 
 int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *);
 #ifdef INET6
_______________________________________________
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