Date: Thu, 7 May 2020 00:26:14 +0000 (UTC) From: Michael Tuexen <tuexen@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r360725 - stable/11/sys/netinet Message-ID: <202005070026.0470QEXt016038@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: tuexen Date: Thu May 7 00:26:13 2020 New Revision: 360725 URL: https://svnweb.freebsd.org/changeset/base/360725 Log: MFC r350520: Fix reporting of unknown paramters in an INIT chunk Fix the reporting of multiple unknown parameters in an received INIT chunk. This also plugs an potential mbuf leak. Thanks to Felix Weinrank for reporting this issue found by fuzz-testing the userland stack. Modified: stable/11/sys/netinet/sctp_output.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/netinet/sctp_output.c ============================================================================== --- stable/11/sys/netinet/sctp_output.c Thu May 7 00:23:07 2020 (r360724) +++ stable/11/sys/netinet/sctp_output.c Thu May 7 00:26:13 2020 (r360725) @@ -4981,17 +4981,17 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_ */ struct sctp_paramhdr *phdr, params; - struct mbuf *mat, *op_err; + struct mbuf *mat, *m_tmp, *op_err, *op_err_last; int at, limit, pad_needed; uint16_t ptype, plen, padded_size; - int err_at; *abort_processing = 0; mat = in_initpkt; - err_at = 0; limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk); at = param_offset; op_err = NULL; + op_err_last = NULL; + pad_needed = 0; SCTPDBG(SCTP_DEBUG_OUTPUT1, "Check for unrecognized param's\n"); phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params)); while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) { @@ -5116,6 +5116,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_ *abort_processing = 1; sctp_m_freem(op_err); op_err = NULL; + op_err_last = NULL; #ifdef INET6 l_len = SCTP_MIN_OVERHEAD; #else @@ -5124,7 +5125,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_ l_len += sizeof(struct sctp_chunkhdr); l_len += sizeof(struct sctp_gen_error_cause); op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); - if (op_err) { + if (op_err != NULL) { /* * Pre-reserve space for IP, SCTP, * and chunk header. @@ -5144,6 +5145,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_ if (SCTP_BUF_NEXT(op_err) == NULL) { sctp_m_freem(op_err); op_err = NULL; + op_err_last = NULL; } } return (op_err); @@ -5179,37 +5181,55 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_ #endif SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + op_err_last = op_err; } } - if (op_err) { + if (op_err != NULL) { /* If we have space */ - struct sctp_paramhdr s; + struct sctp_paramhdr *param; - if (err_at % 4) { - uint32_t cpthis = 0; - - pad_needed = 4 - (err_at % 4); - m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis); - err_at += pad_needed; + if (pad_needed > 0) { + op_err_last = sctp_add_pad_tombuf(op_err_last, pad_needed); } - s.param_type = htons(SCTP_UNRECOG_PARAM); - s.param_length = htons((uint16_t)sizeof(struct sctp_paramhdr) + plen); - m_copyback(op_err, err_at, sizeof(struct sctp_paramhdr), (caddr_t)&s); - err_at += sizeof(struct sctp_paramhdr); - SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT); - if (SCTP_BUF_NEXT(op_err) == NULL) { + if (op_err_last == NULL) { sctp_m_freem(op_err); - /* - * we are out of memory but - * we still need to have a - * look at what to do (the - * system is in trouble - * though). - */ op_err = NULL; + op_err_last = NULL; goto more_processing; } - err_at += plen; + if (M_TRAILINGSPACE(op_err_last) < (int)sizeof(struct sctp_paramhdr)) { + m_tmp = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); + if (m_tmp == NULL) { + sctp_m_freem(op_err); + op_err = NULL; + op_err_last = NULL; + goto more_processing; + } + SCTP_BUF_LEN(m_tmp) = 0; + SCTP_BUF_NEXT(m_tmp) = NULL; + SCTP_BUF_NEXT(op_err_last) = m_tmp; + op_err_last = m_tmp; + } + param = (struct sctp_paramhdr *)(mtod(op_err_last, caddr_t)+SCTP_BUF_LEN(op_err_last)); + param->param_type = htons(SCTP_UNRECOG_PARAM); + param->param_length = htons((uint16_t)sizeof(struct sctp_paramhdr) + plen); + SCTP_BUF_LEN(op_err_last) += sizeof(struct sctp_paramhdr); + SCTP_BUF_NEXT(op_err_last) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT); + if (SCTP_BUF_NEXT(op_err_last) == NULL) { + sctp_m_freem(op_err); + op_err = NULL; + op_err_last = NULL; + goto more_processing; + } else { + while (SCTP_BUF_NEXT(op_err_last) != NULL) { + op_err_last = SCTP_BUF_NEXT(op_err_last); + } + } + if (plen % 4 != 0) { + pad_needed = 4 - (plen % 4); + } else { + pad_needed = 0; + } } } more_processing: @@ -5232,6 +5252,7 @@ invalid_size: *abort_processing = 1; sctp_m_freem(op_err); op_err = NULL; + op_err_last = NULL; if (phdr != NULL) { struct sctp_paramhdr *param; int l_len;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202005070026.0470QEXt016038>