Bug 1683964: Improve the input validation and processing of sctp cookies. r=jesup
authorNils Ohlmeier [:drno] <drno@ohlmeier.org>
Mon, 04 Jan 2021 19:40:16 +0000 (2021-01-04)
changeset 561935 08ba03dc8d4420e04e7c77fee3013e68180e6ead
parent 561934 5712fdcdf04f0573e30c5fcf14515fd27205114c
child 561936 8c09f4813fc7e8f44605b6092262199bff15cdd7
push id38075
push userdluca@mozilla.com
push dateTue, 05 Jan 2021 04:31:31 +0000 (2021-01-05)
treeherdermozilla-central@1d89f3cb5bb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1683964
milestone86.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1683964: Improve the input validation and processing of sctp cookies. r=jesup Differential Revision: https://phabricator.services.mozilla.com/D100379
netwerk/sctp/src/netinet/sctp_input.c
netwerk/sctp/src/netinet/sctp_pcb.c
--- a/netwerk/sctp/src/netinet/sctp_input.c
+++ b/netwerk/sctp/src/netinet/sctp_input.c
@@ -2256,20 +2256,16 @@ sctp_process_cookie_new(struct mbuf *m, 
 		sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
 		                       src, dst, sh, op_err,
 #if defined(__FreeBSD__) && !defined(__Userspace__)
 		                       mflowtype, mflowid,
 #endif
 		                       vrf_id, port);
 		return (NULL);
 	}
-	/* get the correct sctp_nets */
-	if (netp)
-		*netp = sctp_findnet(stcb, init_src);
-
 	asoc = &stcb->asoc;
 	/* get scope variables out of cookie */
 	asoc->scope.ipv4_local_scope = cookie->ipv4_scope;
 	asoc->scope.site_scope = cookie->site_scope;
 	asoc->scope.local_scope = cookie->local_scope;
 	asoc->scope.loopback_scope = cookie->loopback_scope;
 
 #if defined(__Userspace__)
@@ -2316,20 +2312,17 @@ sctp_process_cookie_new(struct mbuf *m, 
 	asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number;
 	asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
 	asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1;
 	asoc->str_reset_seq_in = asoc->init_seq_number;
 
 	asoc->advanced_peer_ack_point = asoc->last_acked_seq;
 
 	/* process the INIT info (peer's info) */
-	if (netp)
-		retval = sctp_process_init(init_cp, stcb);
-	else
-		retval = 0;
+	retval = sctp_process_init(init_cp, stcb);
 	if (retval < 0) {
 #if defined(__APPLE__) && !defined(__Userspace__)
 		atomic_add_int(&stcb->asoc.refcnt, 1);
 		SCTP_TCB_UNLOCK(stcb);
 		SCTP_SOCKET_LOCK(so, 1);
 		SCTP_TCB_LOCK(stcb);
 		atomic_subtract_int(&stcb->asoc.refcnt, 1);
 #endif
@@ -2502,29 +2495,31 @@ sctp_process_cookie_new(struct mbuf *m, 
 	           (SCTP_IS_LISTENING(inp))) {
 		/*
 		 * We don't want to do anything with this one. Since it is
 		 * the listening guy. The timer will get started for
 		 * accepted connections in the caller.
 		 */
 		;
 	}
-	/* since we did not send a HB make sure we don't double things */
-	if ((netp) && (*netp))
-		(*netp)->hb_responded = 1;
-
 	if (stcb->asoc.sctp_autoclose_ticks &&
 	    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
 		sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL);
 	}
 	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
-	if ((netp != NULL) && (*netp != NULL)) {
+	*netp = sctp_findnet(stcb, init_src);
+	if (*netp != NULL) {
 		struct timeval old;
 
-		/* calculate the RTT and set the encaps port */
+		/*
+		 * Since we did not send a HB, make sure we don't double
+		 * things.
+		 */
+		(*netp)->hb_responded = 1;
+		/* Calculate the RTT. */
 		old.tv_sec = cookie->time_entered.tv_sec;
 		old.tv_usec = cookie->time_entered.tv_usec;
 		sctp_calculate_rto(stcb, asoc, *netp, &old, SCTP_RTT_FROM_NON_DATA);
 	}
 	/* respond with a COOKIE-ACK */
 	sctp_send_cookie_ack(stcb);
 
 	/*
--- a/netwerk/sctp/src/netinet/sctp_pcb.c
+++ b/netwerk/sctp/src/netinet/sctp_pcb.c
@@ -4953,17 +4953,25 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, 
 	case AF_INET:
 	{
 		struct sockaddr_in *sin;
 
 		sin = (struct sockaddr_in *)firstaddr;
 		if ((ntohs(sin->sin_port) == 0) ||
 		    (sin->sin_addr.s_addr == INADDR_ANY) ||
 		    (sin->sin_addr.s_addr == INADDR_BROADCAST) ||
-		    IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
+		    IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) ||
+#if defined(__Userspace__)
+		    (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) != 0) ||
+		     (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) != 0) &&
+		      (SCTP_IPV6_V6ONLY(inp) != 0)))) {
+#else
+		    (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) != 0) &&
+		     (SCTP_IPV6_V6ONLY(inp) != 0))) {
+#endif
 			/* Invalid address */
 			SCTP_INP_RUNLOCK(inp);
 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
 			*error = EINVAL;
 			return (NULL);
 		}
 		rport = sin->sin_port;
 		break;
@@ -4972,17 +4980,18 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, 
 #ifdef INET6
 	case AF_INET6:
 	{
 		struct sockaddr_in6 *sin6;
 
 		sin6 = (struct sockaddr_in6 *)firstaddr;
 		if ((ntohs(sin6->sin6_port) == 0) ||
 		    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
-		    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
+		    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) ||
+		    ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)) {
 			/* Invalid address */
 			SCTP_INP_RUNLOCK(inp);
 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
 			*error = EINVAL;
 			return (NULL);
 		}
 		rport = sin6->sin6_port;
 		break;
@@ -4990,17 +4999,18 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, 
 #endif
 #if defined(__Userspace__)
 	case AF_CONN:
 	{
 		struct sockaddr_conn *sconn;
 
 		sconn = (struct sockaddr_conn *)firstaddr;
 		if ((ntohs(sconn->sconn_port) == 0) ||
-		    (sconn->sconn_addr == NULL)) {
+		    (sconn->sconn_addr == NULL) ||
+		    ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) == 0)) {
 			/* Invalid address */
 			SCTP_INP_RUNLOCK(inp);
 			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL);
 			*error = EINVAL;
 			return (NULL);
 		}
 		rport = sconn->sconn_port;
 		break;