From owner-svn-src-stable-12@freebsd.org Sat Sep 7 12:19:08 2019 Return-Path: Delivered-To: svn-src-stable-12@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id AD93BD0889; Sat, 7 Sep 2019 12:19:08 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46QYPm43CXz4W4S; Sat, 7 Sep 2019 12:19:08 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 6E555569A; Sat, 7 Sep 2019 12:19:08 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x87CJ8gx068040; Sat, 7 Sep 2019 12:19:08 GMT (envelope-from tuexen@FreeBSD.org) Received: (from tuexen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x87CJ7gZ068037; Sat, 7 Sep 2019 12:19:07 GMT (envelope-from tuexen@FreeBSD.org) Message-Id: <201909071219.x87CJ7gZ068037@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tuexen set sender to tuexen@FreeBSD.org using -f From: Michael Tuexen Date: Sat, 7 Sep 2019 12:19:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r352007 - stable/12/sys/netinet X-SVN-Group: stable-12 X-SVN-Commit-Author: tuexen X-SVN-Commit-Paths: stable/12/sys/netinet X-SVN-Commit-Revision: 352007 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-12@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for only the 12-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 07 Sep 2019 12:19:08 -0000 Author: tuexen Date: Sat Sep 7 12:19:07 2019 New Revision: 352007 URL: https://svnweb.freebsd.org/changeset/base/352007 Log: MFC r351654: Improve the handling of state cookie parameters in INIT-ACK chunks. This fixes problem with parameters indicating a zero length or partial parameters after an unknown parameter indicating to stop processing. It also fixes a problem with state cookie parameters after unknown parametes indicating to stop porcessing. Thanks to Mark Wodrich from Google for finding two of these issues by fuzz testing the userland stack and reporting them in https://github.com/sctplab/usrsctp/issues/351 and https://github.com/sctplab/usrsctp/issues/352 Modified: stable/12/sys/netinet/sctp_input.c stable/12/sys/netinet/sctp_output.c stable/12/sys/netinet/sctp_output.h Directory Properties: stable/12/ (props changed) Modified: stable/12/sys/netinet/sctp_input.c ============================================================================== --- stable/12/sys/netinet/sctp_input.c Sat Sep 7 12:15:23 2019 (r352006) +++ stable/12/sys/netinet/sctp_input.c Sat Sep 7 12:19:07 2019 (r352007) @@ -444,22 +444,48 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int { struct sctp_association *asoc; struct mbuf *op_err; - int retval, abort_flag; - uint32_t initack_limit; + int retval, abort_flag, cookie_found; + int initack_limit; int nat_friendly = 0; /* First verify that we have no illegal param's */ abort_flag = 0; + cookie_found = 0; op_err = sctp_arethere_unrecognized_parameters(m, (offset + sizeof(struct sctp_init_chunk)), - &abort_flag, (struct sctp_chunkhdr *)cp, &nat_friendly); + &abort_flag, (struct sctp_chunkhdr *)cp, + &nat_friendly, &cookie_found); if (abort_flag) { /* Send an abort and notify peer */ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_no_unlock = 1; return (-1); } + if (!cookie_found) { + uint16_t len; + + len = (uint16_t)(sizeof(struct sctp_error_missing_param) + sizeof(uint16_t)); + /* We abort with an error of missing mandatory param */ + op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); + if (op_err != NULL) { + struct sctp_error_missing_param *cause; + + SCTP_BUF_LEN(op_err) = len; + cause = mtod(op_err, struct sctp_error_missing_param *); + /* Subtract the reserved param */ + cause->cause.code = htons(SCTP_CAUSE_MISSING_PARAM); + cause->cause.length = htons(len); + cause->num_missing_params = htonl(1); + cause->type[0] = htons(SCTP_STATE_COOKIE); + } + sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, + src, dst, sh, op_err, + mflowtype, mflowid, + vrf_id, net->port); + *abort_no_unlock = 1; + return (-3); + } asoc = &stcb->asoc; asoc->peer_supports_nat = (uint8_t)nat_friendly; /* process the peer's parameters in the INIT-ACK */ @@ -524,40 +550,8 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int /* calculate the RTO */ net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, SCTP_RTT_FROM_NON_DATA); - retval = sctp_send_cookie_echo(m, offset, stcb, net); - if (retval < 0) { - /* - * No cookie, we probably should send a op error. But in any - * case if there is no cookie in the INIT-ACK, we can - * abandon the peer, its broke. - */ - if (retval == -3) { - uint16_t len; - - len = (uint16_t)(sizeof(struct sctp_error_missing_param) + sizeof(uint16_t)); - /* We abort with an error of missing mandatory param */ - op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); - if (op_err != NULL) { - struct sctp_error_missing_param *cause; - - SCTP_BUF_LEN(op_err) = len; - cause = mtod(op_err, struct sctp_error_missing_param *); - /* Subtract the reserved param */ - cause->cause.code = htons(SCTP_CAUSE_MISSING_PARAM); - cause->cause.length = htons(len); - cause->num_missing_params = htonl(1); - cause->type[0] = htons(SCTP_STATE_COOKIE); - } - sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, - src, dst, sh, op_err, - mflowtype, mflowid, - vrf_id, net->port); - *abort_no_unlock = 1; - } - return (retval); - } - - return (0); + retval = sctp_send_cookie_echo(m, offset, initack_limit, stcb, net); + return (retval); } static void Modified: stable/12/sys/netinet/sctp_output.c ============================================================================== --- stable/12/sys/netinet/sctp_output.c Sat Sep 7 12:15:23 2019 (r352006) +++ stable/12/sys/netinet/sctp_output.c Sat Sep 7 12:19:07 2019 (r352007) @@ -4970,7 +4970,10 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp struct mbuf * sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, - int param_offset, int *abort_processing, struct sctp_chunkhdr *cp, int *nat_friendly) + int param_offset, int *abort_processing, + struct sctp_chunkhdr *cp, + int *nat_friendly, + int *cookie_found) { /* * Given a mbuf containing an INIT or INIT-ACK with the param_offset @@ -4993,6 +4996,9 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_ uint16_t ptype, plen, padded_size; *abort_processing = 0; + if (cookie_found != NULL) { + *cookie_found = 0; + } mat = in_initpkt; limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk); at = param_offset; @@ -5021,12 +5027,17 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_ switch (ptype) { /* Param's with variable size */ case SCTP_HEARTBEAT_INFO: - case SCTP_STATE_COOKIE: case SCTP_UNRECOG_PARAM: case SCTP_ERROR_CAUSE_IND: /* ok skip fwd */ at += padded_size; break; + case SCTP_STATE_COOKIE: + if (cookie_found != NULL) { + *cookie_found = 1; + } + at += padded_size; + break; /* Param's with variable size within a range */ case SCTP_CHUNK_LIST: case SCTP_SUPPORTED_CHUNK_EXT: @@ -5568,7 +5579,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct abort_flag = 0; op_err = sctp_arethere_unrecognized_parameters(init_pkt, (offset + sizeof(struct sctp_init_chunk)), - &abort_flag, (struct sctp_chunkhdr *)init_chk, &nat_friendly); + &abort_flag, + (struct sctp_chunkhdr *)init_chk, + &nat_friendly, NULL); if (abort_flag) { do_a_abort: if (op_err == NULL) { @@ -9001,7 +9014,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf * int sctp_send_cookie_echo(struct mbuf *m, - int offset, + int offset, int limit, struct sctp_tcb *stcb, struct sctp_nets *net) { @@ -9027,18 +9040,30 @@ sctp_send_cookie_echo(struct mbuf *m, } ptype = ntohs(phdr->param_type); plen = ntohs(phdr->param_length); + if (plen < sizeof(struct sctp_paramhdr)) { + return (-6); + } if (ptype == SCTP_STATE_COOKIE) { int pad; /* found the cookie */ - if ((pad = (plen % 4))) { - plen += 4 - pad; + if (at + plen > limit) { + return (-7); } cookie = SCTP_M_COPYM(m, at, plen, M_NOWAIT); if (cookie == NULL) { /* No memory */ return (-2); } + if ((pad = (plen % 4)) > 0) { + pad = 4 - pad; + } + if (pad > 0) { + cookie = sctp_pad_lastmbuf(cookie, pad, NULL); + if (cookie == NULL) { + return (-8); + } + } #ifdef SCTP_MBUF_LOGGING if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { sctp_log_mbc(cookie, SCTP_MBUF_ICOPY); @@ -9064,7 +9089,7 @@ sctp_send_cookie_echo(struct mbuf *m, chk->rec.chunk_id.id = SCTP_COOKIE_ECHO; chk->rec.chunk_id.can_take_data = 0; chk->flags = CHUNK_FLAGS_FRAGMENT_OK; - chk->send_size = plen; + chk->send_size = SCTP_SIZE32(plen); chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; chk->asoc = &stcb->asoc; Modified: stable/12/sys/netinet/sctp_output.h ============================================================================== --- stable/12/sys/netinet/sctp_output.h Sat Sep 7 12:15:23 2019 (r352006) +++ stable/12/sys/netinet/sctp_output.h Sat Sep 7 12:19:07 2019 (r352007) @@ -92,11 +92,11 @@ sctp_send_initiate_ack(struct sctp_inpcb *, struct sct struct mbuf * sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *, - struct sctp_chunkhdr *, int *); + struct sctp_chunkhdr *, int *, int *); void sctp_queue_op_err(struct sctp_tcb *, struct mbuf *); int -sctp_send_cookie_echo(struct mbuf *, int, struct sctp_tcb *, +sctp_send_cookie_echo(struct mbuf *, int, int, struct sctp_tcb *, struct sctp_nets *); void sctp_send_cookie_ack(struct sctp_tcb *);