Author: tuexen
Date: Sun May 19 17:28:00 2019
New Revision: 347975
URL: https://svnweb.freebsd.org/changeset/base/347975

Log:
  Improve input validation for the IPPROTO_SCTP level socket options
  SCTP_CONNECT_X and SCTP_CONNECT_X_DELAYED.
  
  Some issues where found by running syzkaller.
  
  MFC after:            3 days

Modified:
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c
  head/sys/netinet/sctputil.h

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c      Sun May 19 16:56:59 2019        
(r347974)
+++ head/sys/netinet/sctp_usrreq.c      Sun May 19 17:28:00 2019        
(r347975)
@@ -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

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c Sun May 19 16:56:59 2019        (r347974)
+++ head/sys/netinet/sctputil.c Sun May 19 17:28:00 2019        (r347975)
@@ -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: head/sys/netinet/sctputil.h
==============================================================================
--- head/sys/netinet/sctputil.h Sun May 19 16:56:59 2019        (r347974)
+++ head/sys/netinet/sctputil.h Sun May 19 17:28:00 2019        (r347975)
@@ -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
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to