Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Mar 2019 18:47:41 +0000 (UTC)
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r344708 - head/sys/netinet
Message-ID:  <201903011847.x21Ilfhm086213@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903011847.x21Ilfhm086213>