Date: Thu, 10 Oct 2019 18:19:22 +0000 (UTC) From: Michael Tuexen <tuexen@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org Subject: svn commit: r353410 - releng/12.1/sys/netinet Message-ID: <201910101819.x9AIJMKj089203@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: tuexen Date: Thu Oct 10 18:19:22 2019 New Revision: 353410 URL: https://svnweb.freebsd.org/changeset/base/353410 Log: MFS r353395: Add missing input validation. This could result in reading from uninitialized memory. The issue was found by OSS-Fuzz for usrsctp and reported in https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=17780 MFS r353396: Cleanup sctp_asconf_error_response() and ensure that the parameter is padded as required. This fixes the followig bug reported by OSS-Fuzz for the usersctp stack: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=17790 MFS r353397: When skipping the address parameter, take the padding into account. MFS r353398: Fix the adding of padding to COOKIE-ECHO chunks. Thanks to Mark Wodrich who found this issue while fuzz testing the usrsctp stack and reported the issue in https://github.com/sctplab/usrsctp/issues/382 MFS r353399: Plumb an mbuf leak found by Mark Wodrich from Google by fuzz testing the userland stack and reporting it in: https://github.com/sctplab/usrsctp/issues/396 MFS r353400: Fix a use after free bug when removing remote addresses. This bug was found by OSS-Fuzz and reported in https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=18004 MFS r353401: Plumb an mbuf leak in a code path that should not be taken. Also avoid that this path is taken by setting the tail pointer correctly. There is still bug related to handling unordered unfragmented messages which were delayed in deferred handling. This issue was found by OSS-Fuzz testing the usrsctp stack and reported in https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=17794 MFS r353403: Validate length before use it, not vice versa. r353060 should have contained this... This fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=18070 Approved by: re (gjb@) Modified: releng/12.1/sys/netinet/sctp_asconf.c releng/12.1/sys/netinet/sctp_indata.c releng/12.1/sys/netinet/sctp_input.c releng/12.1/sys/netinet/sctp_output.c Directory Properties: releng/12.1/ (props changed) Modified: releng/12.1/sys/netinet/sctp_asconf.c ============================================================================== --- releng/12.1/sys/netinet/sctp_asconf.c Thu Oct 10 17:29:47 2019 (r353409) +++ releng/12.1/sys/netinet/sctp_asconf.c Thu Oct 10 18:19:22 2019 (r353410) @@ -105,42 +105,47 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause struct mbuf *m_reply = NULL; struct sctp_asconf_paramhdr *aph; struct sctp_error_cause *error; + size_t buf_len; + uint16_t i, param_length, cause_length, padding_length; uint8_t *tlv; - m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) + - tlv_length + - sizeof(struct sctp_error_cause)), - 0, M_NOWAIT, 1, MT_DATA); + if (error_tlv == NULL) { + tlv_length = 0; + } + cause_length = sizeof(struct sctp_error_cause) + tlv_length; + param_length = sizeof(struct sctp_asconf_paramhdr) + cause_length; + padding_length = tlv_length % 4; + if (padding_length != 0) { + padding_length = 4 - padding_length; + } + buf_len = param_length + padding_length; + if (buf_len > MLEN) { + SCTPDBG(SCTP_DEBUG_ASCONF1, + "asconf_error_response: tlv_length (%xh) too big\n", + tlv_length); + return (NULL); + } + m_reply = sctp_get_mbuf_for_msg(buf_len, 0, M_NOWAIT, 1, MT_DATA); if (m_reply == NULL) { SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_error_response: couldn't get mbuf!\n"); return (NULL); } aph = mtod(m_reply, struct sctp_asconf_paramhdr *); - error = (struct sctp_error_cause *)(aph + 1); - - aph->correlation_id = id; aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND); + aph->ph.param_length = htons(param_length); + aph->correlation_id = id; + error = (struct sctp_error_cause *)(aph + 1); error->code = htons(cause); - error->length = tlv_length + sizeof(struct sctp_error_cause); - aph->ph.param_length = error->length + - sizeof(struct sctp_asconf_paramhdr); - - if (aph->ph.param_length > MLEN) { - SCTPDBG(SCTP_DEBUG_ASCONF1, - "asconf_error_response: tlv_length (%xh) too big\n", - tlv_length); - sctp_m_freem(m_reply); /* discard */ - return (NULL); - } + error->length = htons(cause_length); if (error_tlv != NULL) { tlv = (uint8_t *)(error + 1); memcpy(tlv, error_tlv, tlv_length); + for (i = 0; i < padding_length; i++) { + tlv[tlv_length + i] = 0; + } } - SCTP_BUF_LEN(m_reply) = aph->ph.param_length; - error->length = htons(error->length); - aph->ph.param_length = htons(aph->ph.param_length); - + SCTP_BUF_LEN(m_reply) = buf_len; return (m_reply); } @@ -169,10 +174,16 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struc #endif aparam_length = ntohs(aph->ph.param_length); + if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) { + return (NULL); + } ph = (struct sctp_paramhdr *)(aph + 1); param_type = ntohs(ph->param_type); #if defined(INET) || defined(INET6) param_length = ntohs(ph->param_length); + if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) { + return (NULL); + } #endif sa = &store.sa; switch (param_type) { @@ -272,7 +283,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struc static int sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src) { - struct sctp_nets *src_net, *net; + struct sctp_nets *src_net, *net, *nnet; /* make sure the source address exists as a destination net */ src_net = sctp_findnet(stcb, src); @@ -282,10 +293,9 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *s } /* delete all destination addresses except the source */ - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) { if (net != src_net) { /* delete this address */ - sctp_remove_net(stcb, net); SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_del_remote_addrs_except: deleting "); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, @@ -293,6 +303,7 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *s /* notify upper layer */ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED); + sctp_remove_net(stcb, net); } } return (0); @@ -323,10 +334,16 @@ sctp_process_asconf_delete_ip(struct sockaddr *src, #endif aparam_length = ntohs(aph->ph.param_length); + if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) { + return (NULL); + } ph = (struct sctp_paramhdr *)(aph + 1); param_type = ntohs(ph->param_type); #if defined(INET) || defined(INET6) param_length = ntohs(ph->param_length); + if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) { + return (NULL); + } #endif sa = &store.sa; switch (param_type) { @@ -454,10 +471,16 @@ sctp_process_asconf_set_primary(struct sockaddr *src, #endif aparam_length = ntohs(aph->ph.param_length); + if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) { + return (NULL); + } ph = (struct sctp_paramhdr *)(aph + 1); param_type = ntohs(ph->param_type); #if defined(INET) || defined(INET6) param_length = ntohs(ph->param_length); + if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) { + return (NULL); + } #endif sa = &store.sa; switch (param_type) { @@ -676,8 +699,8 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset sctp_m_freem(m_ack); return; } - /* param_length is already validated in process_control... */ - offset += ntohs(p_addr->ph.param_length); /* skip lookup addr */ + /* skip lookup addr */ + offset += SCTP_SIZE32(ntohs(p_addr->ph.param_length)); /* get pointer to first asconf param in ASCONF */ aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf); if (aph == NULL) { @@ -762,8 +785,6 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset if (m_result != NULL) { SCTP_BUF_NEXT(m_tail) = m_result; m_tail = m_result; - /* update lengths, make sure it's aligned too */ - SCTP_BUF_LEN(m_result) = SCTP_SIZE32(SCTP_BUF_LEN(m_result)); ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result); /* set flag to force success reports */ error = 1; Modified: releng/12.1/sys/netinet/sctp_indata.c ============================================================================== --- releng/12.1/sys/netinet/sctp_indata.c Thu Oct 10 17:29:47 2019 (r353409) +++ releng/12.1/sys/netinet/sctp_indata.c Thu Oct 10 18:19:22 2019 (r353410) @@ -716,6 +716,7 @@ sctp_add_to_tail_pointer(struct sctp_queued_to_read *c } if (control->tail_mbuf == NULL) { /* TSNH */ + sctp_m_freem(control->data); control->data = m; sctp_setup_tail_pointer(control); return; @@ -2119,10 +2120,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struc struct mbuf *mm; control->data = dmbuf; + control->tail_mbuf = NULL; for (mm = control->data; mm; mm = mm->m_next) { control->length += SCTP_BUF_LEN(mm); + if (SCTP_BUF_NEXT(mm) == NULL) { + control->tail_mbuf = mm; + } } - control->tail_mbuf = NULL; control->end_added = 1; control->last_frag_seen = 1; control->first_frag_seen = 1; Modified: releng/12.1/sys/netinet/sctp_input.c ============================================================================== --- releng/12.1/sys/netinet/sctp_input.c Thu Oct 10 17:29:47 2019 (r353409) +++ releng/12.1/sys/netinet/sctp_input.c Thu Oct 10 18:19:22 2019 (r353410) @@ -465,6 +465,10 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int if (!cookie_found) { uint16_t len; + /* Only report the missing cookie parameter */ + if (op_err != NULL) { + sctp_m_freem(op_err); + } 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); Modified: releng/12.1/sys/netinet/sctp_output.c ============================================================================== --- releng/12.1/sys/netinet/sctp_output.c Thu Oct 10 17:29:47 2019 (r353409) +++ releng/12.1/sys/netinet/sctp_output.c Thu Oct 10 18:19:22 2019 (r353410) @@ -9059,8 +9059,7 @@ sctp_send_cookie_echo(struct mbuf *m, pad = 4 - pad; } if (pad > 0) { - cookie = sctp_pad_lastmbuf(cookie, pad, NULL); - if (cookie == NULL) { + if (sctp_pad_lastmbuf(cookie, pad, NULL) == NULL) { return (-8); } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910101819.x9AIJMKj089203>