diff --git a/patches/config.json b/patches/config.json index 14315cfaecc80..2a99d01abe083 100644 --- a/patches/config.json +++ b/patches/config.json @@ -15,5 +15,7 @@ "src/electron/patches/sqlite": "src/third_party/sqlite/src", - "src/electron/patches/icu": "src/third_party/icu" + "src/electron/patches/icu": "src/third_party/icu", + + "src/electron/patches/usrsctp": "src/third_party/usrsctp/usrsctplib" } diff --git a/patches/usrsctp/.patches b/patches/usrsctp/.patches new file mode 100644 index 0000000000000..a679b67919e29 --- /dev/null +++ b/patches/usrsctp/.patches @@ -0,0 +1,3 @@ +cherry_picking_improve_the_input_validation_and_processing_of.patch +cherry_picking_clean_up_more_resources_of_an_existing_sctp.patch +cherry_picking_harden_the_handling_of_outgoing_streams.patch diff --git a/patches/usrsctp/cherry_picking_clean_up_more_resources_of_an_existing_sctp.patch b/patches/usrsctp/cherry_picking_clean_up_more_resources_of_an_existing_sctp.patch new file mode 100644 index 0000000000000..6273e9c63990e --- /dev/null +++ b/patches/usrsctp/cherry_picking_clean_up_more_resources_of_an_existing_sctp.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Tuexen +Date: Sat, 12 Dec 2020 23:30:59 +0100 +Subject: Cherry picking: Clean up more resouces of an existing SCTP + association in case of a restart. + +This fixes a use-after-free scenario, which was reported by Felix +Wilhelm from Google in case a peer is able to modify the cookie. +However, this can also be triggered by an assciation restart under +some specific conditions. + +diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c +index e2f03c73165d8e1ecd08b9f103afe03a3d2adb7f..669b2b2131d6e1e844f98fc10547db1715e6a0bd 100755 +--- a/usrsctplib/netinet/sctp_input.c ++++ b/usrsctplib/netinet/sctp_input.c +@@ -34,7 +34,7 @@ + + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include +-__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 366248 2020-09-29 09:36:06Z tuexen $"); ++__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 368593 2020-12-12 22:23:45Z tuexen $"); + #endif + + #include +@@ -1595,6 +1595,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + struct sctp_association *asoc; + struct sctp_init_chunk *init_cp, init_buf; + struct sctp_init_ack_chunk *initack_cp, initack_buf; ++ struct sctp_asconf_addr *aparam, *naparam; ++ struct sctp_asconf_ack *aack, *naack; ++ struct sctp_tmit_chunk *chk, *nchk; ++ struct sctp_stream_reset_list *strrst, *nstrrst; ++ struct sctp_queued_to_read *sq, *nsq; + struct sctp_nets *net; + struct mbuf *op_err; + struct timeval old; +@@ -1891,8 +1896,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + * kick us so it COULD still take a timeout + * to move these.. but it can't hurt to mark them. + */ +- struct sctp_tmit_chunk *chk; +- TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { ++ TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { + if (chk->sent < SCTP_DATAGRAM_RESEND) { + chk->sent = SCTP_DATAGRAM_RESEND; + sctp_flight_size_decrease(chk); +@@ -2084,6 +2088,57 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + stcb->asoc.strmout[i].next_mid_unordered = 0; + stcb->asoc.strmout[i].last_msg_incomplete = 0; + } ++ TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) { ++ TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp); ++ SCTP_FREE(strrst, SCTP_M_STRESET); ++ } ++ TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) { ++ TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next); ++ if (sq->data) { ++ sctp_m_freem(sq->data); ++ sq->data = NULL; ++ } ++ sctp_free_remote_addr(sq->whoFrom); ++ sq->whoFrom = NULL; ++ sq->stcb = NULL; ++ sctp_free_a_readq(stcb, sq); ++ } ++ TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { ++ TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); ++ if (chk->data) { ++ sctp_m_freem(chk->data); ++ chk->data = NULL; ++ } ++ if (chk->holds_key_ref) ++ sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); ++ sctp_free_remote_addr(chk->whoTo); ++ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); ++ SCTP_DECR_CHK_COUNT(); ++ } ++ TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { ++ TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); ++ if (chk->data) { ++ sctp_m_freem(chk->data); ++ chk->data = NULL; ++ } ++ if (chk->holds_key_ref) ++ sctp_auth_key_release(stcb, chk->auth_keyid, SCTP_SO_LOCKED); ++ sctp_free_remote_addr(chk->whoTo); ++ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); ++ SCTP_DECR_CHK_COUNT(); ++ } ++ TAILQ_FOREACH_SAFE(aparam, &asoc->asconf_queue, next, naparam) { ++ TAILQ_REMOVE(&asoc->asconf_queue, aparam, next); ++ SCTP_FREE(aparam,SCTP_M_ASC_ADDR); ++ } ++ TAILQ_FOREACH_SAFE(aack, &asoc->asconf_ack_sent, next, naack) { ++ TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next); ++ if (aack->data != NULL) { ++ sctp_m_freem(aack->data); ++ } ++ SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), aack); ++ } ++ + /* process the INIT-ACK info (my info) */ + asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); + asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); diff --git a/patches/usrsctp/cherry_picking_harden_the_handling_of_outgoing_streams.patch b/patches/usrsctp/cherry_picking_harden_the_handling_of_outgoing_streams.patch new file mode 100644 index 0000000000000..545b922b4f208 --- /dev/null +++ b/patches/usrsctp/cherry_picking_harden_the_handling_of_outgoing_streams.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Tuexen +Date: Mon, 14 Dec 2020 00:57:51 +0100 +Subject: Cherry picking: Harden the handling of outgoing streams in case of an + restart or INIT collision. + +This avouds an out-of-bounce access in case the peer can +break the cookie signature. Thanks to Felix Wilhelm from Google for +reporting the issue. + +diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c +index 669b2b2131d6e1e844f98fc10547db1715e6a0bd..6a5bdba4264b47e10766467255dd9ebd5d135556 100755 +--- a/usrsctplib/netinet/sctp_input.c ++++ b/usrsctplib/netinet/sctp_input.c +@@ -34,7 +34,7 @@ + + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include +-__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 368593 2020-12-12 22:23:45Z tuexen $"); ++__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 368622 2020-12-13 23:51:51Z tuexen $"); + #endif + + #include +@@ -1886,7 +1886,9 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + NULL); + } + asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); +- asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams); ++ if (asoc->pre_open_streams < asoc->streamoutcnt) { ++ asoc->pre_open_streams = asoc->streamoutcnt; ++ } + + if (ntohl(init_cp->init.initiate_tag) != asoc->peer_vtag) { + /* Ok the peer probably discarded our +@@ -2040,8 +2042,9 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + /* move to OPEN state, if not in SHUTDOWN_SENT */ + SCTP_SET_STATE(stcb, SCTP_STATE_OPEN); + } +- asoc->pre_open_streams = +- ntohs(initack_cp->init.num_outbound_streams); ++ if (asoc->pre_open_streams < asoc->streamoutcnt) { ++ asoc->pre_open_streams = asoc->streamoutcnt; ++ } + asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn); + 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; +@@ -2361,7 +2364,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, + /* process the INIT-ACK info (my info) */ + asoc->my_vtag = ntohl(initack_cp->init.initiate_tag); + asoc->my_rwnd = ntohl(initack_cp->init.a_rwnd); +- asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams); + asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn); + 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; diff --git a/patches/usrsctp/cherry_picking_improve_the_input_validation_and_processing_of.patch b/patches/usrsctp/cherry_picking_improve_the_input_validation_and_processing_of.patch new file mode 100644 index 0000000000000..57aa5f7549770 --- /dev/null +++ b/patches/usrsctp/cherry_picking_improve_the_input_validation_and_processing_of.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Tuexen +Date: Tue, 29 Sep 2020 11:38:11 +0200 +Subject: Cherry picking: Improve the input validation and processing of + cookies. + +This avoids setting the association in an inconsistent +state, which could result in a use-after-free situation. +The issue can be triggered by a malicious peer, if the peer +can modify the cookie without the local endpoint recognizing it. + +Thanks to Ned Williamson for reporting the issue. + +diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c +index 2555eacd68a9bf8c5a29ee190ee6fc03f5c7699c..e2f03c73165d8e1ecd08b9f103afe03a3d2adb7f 100755 +--- a/usrsctplib/netinet/sctp_input.c ++++ b/usrsctplib/netinet/sctp_input.c +@@ -34,7 +34,7 @@ + + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include +-__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 364268 2020-08-16 11:50:37Z tuexen $"); ++__FBSDID("$FreeBSD: head/sys/netinet/sctp_input.c 366248 2020-09-29 09:36:06Z tuexen $"); + #endif + + #include +@@ -2260,10 +2260,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, + 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; +@@ -2320,10 +2316,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, + 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); +@@ -2506,19 +2499,21 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, + */ + ; + } +- /* 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); +diff --git a/usrsctplib/netinet/sctp_pcb.c b/usrsctplib/netinet/sctp_pcb.c +index 2bae796e5ad5c7cc490ceb4fa01c5cc448499232..f439c78eb45969f46cc47ca90cd710279b675071 100755 +--- a/usrsctplib/netinet/sctp_pcb.c ++++ b/usrsctplib/netinet/sctp_pcb.c +@@ -34,7 +34,7 @@ + + #if defined(__FreeBSD__) && !defined(__Userspace__) + #include +-__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 364268 2020-08-16 11:50:37Z tuexen $"); ++__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 366248 2020-09-29 09:36:06Z tuexen $"); + #endif + + #include +@@ -4997,7 +4997,15 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *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); +@@ -5016,7 +5024,8 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, + 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); +@@ -5034,7 +5043,8 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, + + 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);