Author: tuexen
Date: Fri Mar  1 18:47:41 2019
New Revision: 344708
URL: https://svnweb.freebsd.org/changeset/base/344708

Log:
  Honor the memory limits provided when processing the IPPROTO_SCTP
  level socket option SCTP_GET_LOCAL_ADDRESSES in a getsockopt() call.
  
  Thanks to Thomas Barabosch for reporting the issue which was found by
  running syzkaller.
  
  MFC after:            3 days

Modified:
  head/sys/netinet/sctp_usrreq.c

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c      Fri Mar  1 18:12:07 2019        
(r344707)
+++ head/sys/netinet/sctp_usrreq.c      Fri Mar  1 18:47:41 2019        
(r344708)
@@ -1122,12 +1122,18 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
                                                }
 #ifdef INET6
                                                if (sctp_is_feature_on(inp, 
SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
+                                                       if (actual + 
sizeof(struct sockaddr_in6) > limit) {
+                                                               return (actual);
+                                                       }
                                                        
in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
                                                        ((struct sockaddr_in6 
*)sas)->sin6_port = inp->sctp_lport;
                                                        sas = (struct 
sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
                                                        actual += sizeof(struct 
sockaddr_in6);
                                                } else {
 #endif
+                                                       if (actual + 
sizeof(struct sockaddr_in) > limit) {
+                                                               return (actual);
+                                                       }
                                                        memcpy(sas, sin, 
sizeof(struct sockaddr_in));
                                                        ((struct sockaddr_in 
*)sas)->sin_port = inp->sctp_lport;
                                                        sas = (struct 
sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in));
@@ -1135,9 +1141,6 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
 #ifdef INET6
                                                }
 #endif
-                                               if (actual >= limit) {
-                                                       return (actual);
-                                               }
                                        } else {
                                                continue;
                                        }
@@ -1182,13 +1185,13 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
                                                    
(IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
                                                        continue;
                                                }
+                                               if (actual + sizeof(struct 
sockaddr_in6) > limit) {
+                                                       return (actual);
+                                               }
                                                memcpy(sas, sin6, sizeof(struct 
sockaddr_in6));
                                                ((struct sockaddr_in6 
*)sas)->sin6_port = inp->sctp_lport;
                                                sas = (struct sockaddr_storage 
*)((caddr_t)sas + sizeof(struct sockaddr_in6));
                                                actual += sizeof(struct 
sockaddr_in6);
-                                               if (actual >= limit) {
-                                                       return (actual);
-                                               }
                                        } else {
                                                continue;
                                        }
@@ -1202,6 +1205,7 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
                }
        } else {
                struct sctp_laddr *laddr;
+               size_t sa_len;
 
                LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
                        if (stcb) {
@@ -1209,6 +1213,10 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
                                        continue;
                                }
                        }
+                       sa_len = laddr->ifa->address.sa.sa_len;
+                       if (actual + sa_len > limit) {
+                               return (actual);
+                       }
                        if (sctp_fill_user_address(sas, 
&laddr->ifa->address.sa))
                                continue;
                        switch (laddr->ifa->address.sa.sa_family) {
@@ -1226,12 +1234,8 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
                                /* TSNH */
                                break;
                        }
-                       sas = (struct sockaddr_storage *)((caddr_t)sas +
-                           laddr->ifa->address.sa.sa_len);
-                       actual += laddr->ifa->address.sa.sa_len;
-                       if (actual >= limit) {
-                               return (actual);
-                       }
+                       sas = (struct sockaddr_storage *)((caddr_t)sas + 
sa_len);
+                       actual += sa_len;
                }
        }
        return (actual);
_______________________________________________
[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