Bug 1683964: Improve the input validation and processing of sctp cookies. r=jesup, a=RyanVM
Differential Revision:
https://phabricator.services.mozilla.com/D100379
--- 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;