From owner-svn-src-releng@FreeBSD.ORG Tue Jan 27 19:37:08 2015 Return-Path: Delivered-To: svn-src-releng@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 14F7237C; Tue, 27 Jan 2015 19:37:08 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id F1AE3B3D; Tue, 27 Jan 2015 19:37:07 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t0RJb75b015673; Tue, 27 Jan 2015 19:37:07 GMT (envelope-from delphij@FreeBSD.org) Received: (from delphij@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t0RJb3UI015565; Tue, 27 Jan 2015 19:37:03 GMT (envelope-from delphij@FreeBSD.org) Message-Id: <201501271937.t0RJb3UI015565@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: delphij set sender to delphij@FreeBSD.org using -f From: Xin LI Date: Tue, 27 Jan 2015 19:37:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org Subject: svn commit: r277808 - in releng: 10.0 10.0/sys/conf 10.0/sys/netinet 10.1 10.1/sys/conf 10.1/sys/netinet 8.4 8.4/sys/conf 8.4/sys/netinet 9.3 9.3/sys/conf 9.3/sys/netinet X-SVN-Group: releng MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-releng@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the release engineering / security commits to the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Jan 2015 19:37:08 -0000 Author: delphij Date: Tue Jan 27 19:37:02 2015 New Revision: 277808 URL: https://svnweb.freebsd.org/changeset/base/277808 Log: Fix SCTP SCTP_SS_VALUE kernel memory corruption and disclosure vulnerability and SCTP stream reset vulnerability. Security: FreeBSD-SA-15:02.kmem Security: CVE-2014-8612 Security: FreeBSD-SA-15:03.sctp Security: CVE-2014-8613 Approved by: so Modified: releng/10.0/UPDATING releng/10.0/sys/conf/newvers.sh releng/10.0/sys/netinet/sctp_input.c releng/10.0/sys/netinet/sctp_usrreq.c releng/10.1/UPDATING releng/10.1/sys/conf/newvers.sh releng/10.1/sys/netinet/sctp_input.c releng/10.1/sys/netinet/sctp_usrreq.c releng/8.4/UPDATING releng/8.4/sys/conf/newvers.sh releng/8.4/sys/netinet/sctp_input.c releng/8.4/sys/netinet/sctp_usrreq.c releng/9.3/UPDATING releng/9.3/sys/conf/newvers.sh releng/9.3/sys/netinet/sctp_input.c releng/9.3/sys/netinet/sctp_usrreq.c Modified: releng/10.0/UPDATING ============================================================================== --- releng/10.0/UPDATING Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.0/UPDATING Tue Jan 27 19:37:02 2015 (r277808) @@ -16,6 +16,14 @@ from older versions of FreeBSD, try WITH stable/10, and then rebuild without this option. The bootstrap process from older version of current is a bit fragile. +20150127: p17 FreeBSD-SA-15:02.kmem + FreeBSD-SA-15:03.sctp + + Fix SCTP SCTP_SS_VALUE kernel memory corruption and disclosure + vulnerability. [SA-15:02] + + Fix SCTP stream reset vulnerability. [SA-15:03] + 20150114: p16 FreeBSD-SA-15:01.openssl Fix multiple vulnerabilities in OpenSSL. [SA-15:01] Modified: releng/10.0/sys/conf/newvers.sh ============================================================================== --- releng/10.0/sys/conf/newvers.sh Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.0/sys/conf/newvers.sh Tue Jan 27 19:37:02 2015 (r277808) @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="10.0" -BRANCH="RELEASE-p16" +BRANCH="RELEASE-p17" if [ "X${BRANCH_OVERRIDE}" != "X" ]; then BRANCH=${BRANCH_OVERRIDE} fi Modified: releng/10.0/sys/netinet/sctp_input.c ============================================================================== --- releng/10.0/sys/netinet/sctp_input.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.0/sys/netinet/sctp_input.c Tue Jan 27 19:37:02 2015 (r277808) @@ -3690,6 +3690,9 @@ sctp_handle_stream_reset_response(struct /* huh ? */ return (0); } + if (ntohs(respin->ph.param_length) < sizeof(struct sctp_stream_reset_response_tsn)) { + return (0); + } if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { resp = (struct sctp_stream_reset_response_tsn *)respin; asoc->stream_reset_outstanding--; @@ -4078,7 +4081,7 @@ __attribute__((noinline)) sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, struct sctp_chunkhdr *ch_req) { - int chk_length, param_len, ptype; + uint16_t remaining_length, param_len, ptype; struct sctp_paramhdr pstore; uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE]; uint32_t seq = 0; @@ -4091,7 +4094,7 @@ __attribute__((noinline)) int num_param = 0; /* now it may be a reset or a reset-response */ - chk_length = ntohs(ch_req->chunk_length); + remaining_length = ntohs(ch_req->chunk_length) - sizeof(struct sctp_chunkhdr); /* setup for adding the response */ sctp_alloc_a_chunk(stcb, chk); @@ -4127,20 +4130,27 @@ strres_nochunk: ch->chunk_length = htons(chk->send_size); SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); offset += sizeof(struct sctp_chunkhdr); - while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) { + while (remaining_length >= sizeof(struct sctp_paramhdr)) { ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *) & pstore); - if (ph == NULL) + if (ph == NULL) { + /* TSNH */ break; + } param_len = ntohs(ph->param_length); - if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) { - /* bad param */ + if ((param_len > remaining_length) || + (param_len < (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)))) { + /* bad parameter length */ break; } - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)), + ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)), (uint8_t *) & cstore); + if (ph == NULL) { + /* TSNH */ + break; + } ptype = ntohs(ph->param_type); num_param++; - if (param_len > (int)sizeof(cstore)) { + if (param_len > sizeof(cstore)) { trunc = 1; } else { trunc = 0; @@ -4152,6 +4162,9 @@ strres_nochunk: if (ptype == SCTP_STR_RESET_OUT_REQUEST) { struct sctp_stream_reset_out_request *req_out; + if (param_len < sizeof(struct sctp_stream_reset_out_request)) { + break; + } req_out = (struct sctp_stream_reset_out_request *)ph; num_req++; if (stcb->asoc.stream_reset_outstanding) { @@ -4165,12 +4178,18 @@ strres_nochunk: } else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_strm(stcb, chk, str_add); } else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_out_strm(stcb, chk, str_add); @@ -4195,6 +4214,9 @@ strres_nochunk: struct sctp_stream_reset_response *resp; uint32_t result; + if (param_len < sizeof(struct sctp_stream_reset_response)) { + break; + } resp = (struct sctp_stream_reset_response *)ph; seq = ntohl(resp->response_seq); result = ntohl(resp->result); @@ -4206,7 +4228,11 @@ strres_nochunk: break; } offset += SCTP_SIZE32(param_len); - chk_length -= SCTP_SIZE32(param_len); + if (remaining_length >= SCTP_SIZE32(param_len)) { + remaining_length -= SCTP_SIZE32(param_len); + } else { + remaining_length = 0; + } } if (num_req == 0) { /* we have no response free the stuff */ Modified: releng/10.0/sys/netinet/sctp_usrreq.c ============================================================================== --- releng/10.0/sys/netinet/sctp_usrreq.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.0/sys/netinet/sctp_usrreq.c Tue Jan 27 19:37:02 2015 (r277808) @@ -1869,8 +1869,9 @@ flags_out: SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - &av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + &av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } else { @@ -3675,8 +3676,9 @@ sctp_setopt(struct socket *so, int optna SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } @@ -3686,10 +3688,12 @@ sctp_setopt(struct socket *so, int optna SCTP_INP_RLOCK(inp); LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { SCTP_TCB_LOCK(stcb); - stcb->asoc.ss_functions.sctp_ss_set_value(stcb, - &stcb->asoc, - &stcb->asoc.strmout[av->stream_id], - av->stream_value); + if (av->stream_id < stcb->asoc.streamoutcnt) { + stcb->asoc.ss_functions.sctp_ss_set_value(stcb, + &stcb->asoc, + &stcb->asoc.strmout[av->stream_id], + av->stream_value); + } SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp); Modified: releng/10.1/UPDATING ============================================================================== --- releng/10.1/UPDATING Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.1/UPDATING Tue Jan 27 19:37:02 2015 (r277808) @@ -16,6 +16,14 @@ from older versions of FreeBSD, try WITH stable/10, and then rebuild without this option. The bootstrap process from older version of current is a bit fragile. +20150127: p5 FreeBSD-SA-15:02.kmem + FreeBSD-SA-15:03.sctp + + Fix SCTP SCTP_SS_VALUE kernel memory corruption and disclosure + vulnerability. [SA-15:02] + + Fix SCTP stream reset vulnerability. [SA-15:03] + 20150114: p4 FreeBSD-SA-15:01.openssl Fix multiple vulnerabilities in OpenSSL. [SA-15:01] Modified: releng/10.1/sys/conf/newvers.sh ============================================================================== --- releng/10.1/sys/conf/newvers.sh Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.1/sys/conf/newvers.sh Tue Jan 27 19:37:02 2015 (r277808) @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="10.1" -BRANCH="RELEASE-p4" +BRANCH="RELEASE-p5" if [ "X${BRANCH_OVERRIDE}" != "X" ]; then BRANCH=${BRANCH_OVERRIDE} fi Modified: releng/10.1/sys/netinet/sctp_input.c ============================================================================== --- releng/10.1/sys/netinet/sctp_input.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.1/sys/netinet/sctp_input.c Tue Jan 27 19:37:02 2015 (r277808) @@ -3664,6 +3664,9 @@ sctp_handle_stream_reset_response(struct /* huh ? */ return (0); } + if (ntohs(respin->ph.param_length) < sizeof(struct sctp_stream_reset_response_tsn)) { + return (0); + } if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { resp = (struct sctp_stream_reset_response_tsn *)respin; asoc->stream_reset_outstanding--; @@ -4052,7 +4055,7 @@ __attribute__((noinline)) sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, struct sctp_chunkhdr *ch_req) { - int chk_length, param_len, ptype; + uint16_t remaining_length, param_len, ptype; struct sctp_paramhdr pstore; uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE]; uint32_t seq = 0; @@ -4065,7 +4068,7 @@ __attribute__((noinline)) int num_param = 0; /* now it may be a reset or a reset-response */ - chk_length = ntohs(ch_req->chunk_length); + remaining_length = ntohs(ch_req->chunk_length) - sizeof(struct sctp_chunkhdr); /* setup for adding the response */ sctp_alloc_a_chunk(stcb, chk); @@ -4103,20 +4106,27 @@ strres_nochunk: ch->chunk_length = htons(chk->send_size); SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); offset += sizeof(struct sctp_chunkhdr); - while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) { + while (remaining_length >= sizeof(struct sctp_paramhdr)) { ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *) & pstore); - if (ph == NULL) + if (ph == NULL) { + /* TSNH */ break; + } param_len = ntohs(ph->param_length); - if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) { - /* bad param */ + if ((param_len > remaining_length) || + (param_len < (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)))) { + /* bad parameter length */ break; } - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)), + ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)), (uint8_t *) & cstore); + if (ph == NULL) { + /* TSNH */ + break; + } ptype = ntohs(ph->param_type); num_param++; - if (param_len > (int)sizeof(cstore)) { + if (param_len > sizeof(cstore)) { trunc = 1; } else { trunc = 0; @@ -4128,6 +4138,9 @@ strres_nochunk: if (ptype == SCTP_STR_RESET_OUT_REQUEST) { struct sctp_stream_reset_out_request *req_out; + if (param_len < sizeof(struct sctp_stream_reset_out_request)) { + break; + } req_out = (struct sctp_stream_reset_out_request *)ph; num_req++; if (stcb->asoc.stream_reset_outstanding) { @@ -4141,12 +4154,18 @@ strres_nochunk: } else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_strm(stcb, chk, str_add); } else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_out_strm(stcb, chk, str_add); @@ -4171,6 +4190,9 @@ strres_nochunk: struct sctp_stream_reset_response *resp; uint32_t result; + if (param_len < sizeof(struct sctp_stream_reset_response)) { + break; + } resp = (struct sctp_stream_reset_response *)ph; seq = ntohl(resp->response_seq); result = ntohl(resp->result); @@ -4182,7 +4204,11 @@ strres_nochunk: break; } offset += SCTP_SIZE32(param_len); - chk_length -= SCTP_SIZE32(param_len); + if (remaining_length >= SCTP_SIZE32(param_len)) { + remaining_length -= SCTP_SIZE32(param_len); + } else { + remaining_length = 0; + } } if (num_req == 0) { /* we have no response free the stuff */ Modified: releng/10.1/sys/netinet/sctp_usrreq.c ============================================================================== --- releng/10.1/sys/netinet/sctp_usrreq.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/10.1/sys/netinet/sctp_usrreq.c Tue Jan 27 19:37:02 2015 (r277808) @@ -1854,8 +1854,9 @@ flags_out: SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - &av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + &av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } else { @@ -3915,8 +3916,9 @@ sctp_setopt(struct socket *so, int optna SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } @@ -3926,10 +3928,12 @@ sctp_setopt(struct socket *so, int optna SCTP_INP_RLOCK(inp); LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { SCTP_TCB_LOCK(stcb); - stcb->asoc.ss_functions.sctp_ss_set_value(stcb, - &stcb->asoc, - &stcb->asoc.strmout[av->stream_id], - av->stream_value); + if (av->stream_id < stcb->asoc.streamoutcnt) { + stcb->asoc.ss_functions.sctp_ss_set_value(stcb, + &stcb->asoc, + &stcb->asoc.strmout[av->stream_id], + av->stream_value); + } SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp); Modified: releng/8.4/UPDATING ============================================================================== --- releng/8.4/UPDATING Tue Jan 27 19:36:08 2015 (r277807) +++ releng/8.4/UPDATING Tue Jan 27 19:37:02 2015 (r277808) @@ -15,6 +15,14 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8. debugging tools present in HEAD were left in place because sun4v support still needs work to become production ready. +20150127: p23 FreeBSD-SA-15:02.kmem + FreeBSD-SA-15:03.sctp + + Fix SCTP SCTP_SS_VALUE kernel memory corruption and disclosure + vulnerability. [SA-15:02] + + Fix SCTP stream reset vulnerability. [SA-15:03] + 20150114: p22 FreeBSD-SA-15:01.openssl Fix multiple vulnerabilities in OpenSSL. [SA-15:01] Modified: releng/8.4/sys/conf/newvers.sh ============================================================================== --- releng/8.4/sys/conf/newvers.sh Tue Jan 27 19:36:08 2015 (r277807) +++ releng/8.4/sys/conf/newvers.sh Tue Jan 27 19:37:02 2015 (r277808) @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="8.4" -BRANCH="RELEASE-p22" +BRANCH="RELEASE-p23" if [ "X${BRANCH_OVERRIDE}" != "X" ]; then BRANCH=${BRANCH_OVERRIDE} fi Modified: releng/8.4/sys/netinet/sctp_input.c ============================================================================== --- releng/8.4/sys/netinet/sctp_input.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/8.4/sys/netinet/sctp_input.c Tue Jan 27 19:37:02 2015 (r277808) @@ -3680,6 +3680,9 @@ sctp_handle_stream_reset_response(struct /* huh ? */ return (0); } + if (ntohs(respin->ph.param_length) < sizeof(struct sctp_stream_reset_response_tsn)) { + return (0); + } if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { resp = (struct sctp_stream_reset_response_tsn *)respin; asoc->stream_reset_outstanding--; @@ -4068,7 +4071,7 @@ __attribute__((noinline)) sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, struct sctp_chunkhdr *ch_req) { - int chk_length, param_len, ptype; + uint16_t remaining_length, param_len, ptype; struct sctp_paramhdr pstore; uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE]; uint32_t seq = 0; @@ -4081,7 +4084,7 @@ __attribute__((noinline)) int num_param = 0; /* now it may be a reset or a reset-response */ - chk_length = ntohs(ch_req->chunk_length); + remaining_length = ntohs(ch_req->chunk_length) - sizeof(struct sctp_chunkhdr); /* setup for adding the response */ sctp_alloc_a_chunk(stcb, chk); @@ -4117,20 +4120,27 @@ strres_nochunk: ch->chunk_length = htons(chk->send_size); SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); offset += sizeof(struct sctp_chunkhdr); - while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) { + while (remaining_length >= sizeof(struct sctp_paramhdr)) { ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *) & pstore); - if (ph == NULL) + if (ph == NULL) { + /* TSNH */ break; + } param_len = ntohs(ph->param_length); - if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) { - /* bad param */ + if ((param_len > remaining_length) || + (param_len < (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)))) { + /* bad parameter length */ break; } - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)), + ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)), (uint8_t *) & cstore); + if (ph == NULL) { + /* TSNH */ + break; + } ptype = ntohs(ph->param_type); num_param++; - if (param_len > (int)sizeof(cstore)) { + if (param_len > sizeof(cstore)) { trunc = 1; } else { trunc = 0; @@ -4142,6 +4152,9 @@ strres_nochunk: if (ptype == SCTP_STR_RESET_OUT_REQUEST) { struct sctp_stream_reset_out_request *req_out; + if (param_len < sizeof(struct sctp_stream_reset_out_request)) { + break; + } req_out = (struct sctp_stream_reset_out_request *)ph; num_req++; if (stcb->asoc.stream_reset_outstanding) { @@ -4155,12 +4168,18 @@ strres_nochunk: } else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_strm(stcb, chk, str_add); } else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_out_strm(stcb, chk, str_add); @@ -4185,6 +4204,9 @@ strres_nochunk: struct sctp_stream_reset_response *resp; uint32_t result; + if (param_len < sizeof(struct sctp_stream_reset_response)) { + break; + } resp = (struct sctp_stream_reset_response *)ph; seq = ntohl(resp->response_seq); result = ntohl(resp->result); @@ -4196,7 +4218,11 @@ strres_nochunk: break; } offset += SCTP_SIZE32(param_len); - chk_length -= SCTP_SIZE32(param_len); + if (remaining_length >= SCTP_SIZE32(param_len)) { + remaining_length -= SCTP_SIZE32(param_len); + } else { + remaining_length = 0; + } } if (num_req == 0) { /* we have no response free the stuff */ Modified: releng/8.4/sys/netinet/sctp_usrreq.c ============================================================================== --- releng/8.4/sys/netinet/sctp_usrreq.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/8.4/sys/netinet/sctp_usrreq.c Tue Jan 27 19:37:02 2015 (r277808) @@ -1845,8 +1845,9 @@ flags_out: SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - &av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + &av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } else { @@ -3640,8 +3641,9 @@ sctp_setopt(struct socket *so, int optna SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } @@ -3651,10 +3653,12 @@ sctp_setopt(struct socket *so, int optna SCTP_INP_RLOCK(inp); LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { SCTP_TCB_LOCK(stcb); - stcb->asoc.ss_functions.sctp_ss_set_value(stcb, - &stcb->asoc, - &stcb->asoc.strmout[av->stream_id], - av->stream_value); + if (av->stream_id < stcb->asoc.streamoutcnt) { + stcb->asoc.ss_functions.sctp_ss_set_value(stcb, + &stcb->asoc, + &stcb->asoc.strmout[av->stream_id], + av->stream_value); + } SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp); Modified: releng/9.3/UPDATING ============================================================================== --- releng/9.3/UPDATING Tue Jan 27 19:36:08 2015 (r277807) +++ releng/9.3/UPDATING Tue Jan 27 19:37:02 2015 (r277808) @@ -11,6 +11,14 @@ handbook: Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. +20150127: p9 FreeBSD-SA-15:02.kmem + FreeBSD-SA-15:03.sctp + + Fix SCTP SCTP_SS_VALUE kernel memory corruption and disclosure + vulnerability. [SA-15:02] + + Fix SCTP stream reset vulnerability. [SA-15:03] + 20150114: p8 FreeBSD-SA-15:01.openssl Fix multiple vulnerabilities in OpenSSL. [SA-15:01] Modified: releng/9.3/sys/conf/newvers.sh ============================================================================== --- releng/9.3/sys/conf/newvers.sh Tue Jan 27 19:36:08 2015 (r277807) +++ releng/9.3/sys/conf/newvers.sh Tue Jan 27 19:37:02 2015 (r277808) @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="9.3" -BRANCH="RELEASE-p8" +BRANCH="RELEASE-p9" if [ "X${BRANCH_OVERRIDE}" != "X" ]; then BRANCH=${BRANCH_OVERRIDE} fi Modified: releng/9.3/sys/netinet/sctp_input.c ============================================================================== --- releng/9.3/sys/netinet/sctp_input.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/9.3/sys/netinet/sctp_input.c Tue Jan 27 19:37:02 2015 (r277808) @@ -3662,6 +3662,9 @@ sctp_handle_stream_reset_response(struct /* huh ? */ return (0); } + if (ntohs(respin->ph.param_length) < sizeof(struct sctp_stream_reset_response_tsn)) { + return (0); + } if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { resp = (struct sctp_stream_reset_response_tsn *)respin; asoc->stream_reset_outstanding--; @@ -4050,7 +4053,7 @@ __attribute__((noinline)) sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, struct sctp_chunkhdr *ch_req) { - int chk_length, param_len, ptype; + uint16_t remaining_length, param_len, ptype; struct sctp_paramhdr pstore; uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE]; uint32_t seq = 0; @@ -4063,7 +4066,7 @@ __attribute__((noinline)) int num_param = 0; /* now it may be a reset or a reset-response */ - chk_length = ntohs(ch_req->chunk_length); + remaining_length = ntohs(ch_req->chunk_length) - sizeof(struct sctp_chunkhdr); /* setup for adding the response */ sctp_alloc_a_chunk(stcb, chk); @@ -4099,20 +4102,27 @@ strres_nochunk: ch->chunk_length = htons(chk->send_size); SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); offset += sizeof(struct sctp_chunkhdr); - while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) { + while (remaining_length >= sizeof(struct sctp_paramhdr)) { ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *) & pstore); - if (ph == NULL) + if (ph == NULL) { + /* TSNH */ break; + } param_len = ntohs(ph->param_length); - if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) { - /* bad param */ + if ((param_len > remaining_length) || + (param_len < (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)))) { + /* bad parameter length */ break; } - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)), + ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)), (uint8_t *) & cstore); + if (ph == NULL) { + /* TSNH */ + break; + } ptype = ntohs(ph->param_type); num_param++; - if (param_len > (int)sizeof(cstore)) { + if (param_len > sizeof(cstore)) { trunc = 1; } else { trunc = 0; @@ -4124,6 +4134,9 @@ strres_nochunk: if (ptype == SCTP_STR_RESET_OUT_REQUEST) { struct sctp_stream_reset_out_request *req_out; + if (param_len < sizeof(struct sctp_stream_reset_out_request)) { + break; + } req_out = (struct sctp_stream_reset_out_request *)ph; num_req++; if (stcb->asoc.stream_reset_outstanding) { @@ -4137,12 +4150,18 @@ strres_nochunk: } else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_strm(stcb, chk, str_add); } else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_out_strm(stcb, chk, str_add); @@ -4167,6 +4186,9 @@ strres_nochunk: struct sctp_stream_reset_response *resp; uint32_t result; + if (param_len < sizeof(struct sctp_stream_reset_response)) { + break; + } resp = (struct sctp_stream_reset_response *)ph; seq = ntohl(resp->response_seq); result = ntohl(resp->result); @@ -4178,7 +4200,11 @@ strres_nochunk: break; } offset += SCTP_SIZE32(param_len); - chk_length -= SCTP_SIZE32(param_len); + if (remaining_length >= SCTP_SIZE32(param_len)) { + remaining_length -= SCTP_SIZE32(param_len); + } else { + remaining_length = 0; + } } if (num_req == 0) { /* we have no response free the stuff */ Modified: releng/9.3/sys/netinet/sctp_usrreq.c ============================================================================== --- releng/9.3/sys/netinet/sctp_usrreq.c Tue Jan 27 19:36:08 2015 (r277807) +++ releng/9.3/sys/netinet/sctp_usrreq.c Tue Jan 27 19:37:02 2015 (r277808) @@ -1854,8 +1854,9 @@ flags_out: SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - &av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + &av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } else { @@ -3660,8 +3661,9 @@ sctp_setopt(struct socket *so, int optna SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], - av->stream_value) < 0) { + if ((av->stream_id >= stcb->asoc.streamoutcnt) || + (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], + av->stream_value) < 0)) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } @@ -3671,10 +3673,12 @@ sctp_setopt(struct socket *so, int optna SCTP_INP_RLOCK(inp); LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { SCTP_TCB_LOCK(stcb); - stcb->asoc.ss_functions.sctp_ss_set_value(stcb, - &stcb->asoc, - &stcb->asoc.strmout[av->stream_id], - av->stream_value); + if (av->stream_id < stcb->asoc.streamoutcnt) { + stcb->asoc.ss_functions.sctp_ss_set_value(stcb, + &stcb->asoc, + &stcb->asoc.strmout[av->stream_id], + av->stream_value); + } SCTP_TCB_UNLOCK(stcb); } SCTP_INP_RUNLOCK(inp);