svn commit: r360725 - stable/11/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Thu May 7 00:26:14 UTC 2020
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;
More information about the svn-src-all
mailing list