Bug 1683964: Improve the input validation and processing of sctp cookies. r=jesup, a=RyanVM FIREFOX_ESR_78_6_X_RELBRANCH
authorNils Ohlmeier [:drno] <drno@ohlmeier.org>
Mon, 04 Jan 2021 19:40:16 +0000
branchFIREFOX_ESR_78_6_X_RELBRANCH
changeset 600287 4158db020f687f5363f6c1ebcda8d76d690a1359
parent 600286 0bcf7c69ccd1d3120187c2397e9cabd746cdec52
child 600288 a3ea1c463e0e30341a25ea890a693dfe3f75eb19
push id159
push userryanvm@gmail.com
push dateTue, 05 Jan 2021 20:46:13 +0000
treeherdermozilla-esr78@df0581e37d87 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, RyanVM
bugs1683964
milestone78.6.1
Bug 1683964: Improve the input validation and processing of sctp cookies. r=jesup, a=RyanVM 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
@@ -2261,20 +2261,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__)
 		                       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__)
@@ -2321,20 +2317,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(SCTP_SO_LOCK_TESTING)
 		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
@@ -2508,29 +2501,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;
 		(*netp)->RTO = 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
@@ -5015,17 +5015,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;
@@ -5034,17 +5042,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;
@@ -5052,17 +5061,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;