Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: cherry-pick 2c26785, b03de8b and a3c3ef6 from usrsctp. #27491

Merged
merged 2 commits into from Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion patches/config.json
Expand Up @@ -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"
}
3 changes: 3 additions & 0 deletions 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
@@ -0,0 +1,104 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Tuexen <tuexen@fh-muenster.de>
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 <sys/cdefs.h>
-__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 <netinet/sctp_os.h>
@@ -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);
@@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Tuexen <tuexen@fh-muenster.de>
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 <sys/cdefs.h>
-__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 <netinet/sctp_os.h>
@@ -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;
@@ -0,0 +1,127 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Tuexen <tuexen@fh-muenster.de>
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 <sys/cdefs.h>
-__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 <netinet/sctp_os.h>
@@ -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 <sys/cdefs.h>
-__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 <netinet/sctp_os.h>
@@ -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);