svn commit: r351999 - stable/12/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Sat Sep 7 11:52:36 UTC 2019
Author: tuexen
Date: Sat Sep 7 11:52:35 2019
New Revision: 351999
URL: https://svnweb.freebsd.org/changeset/base/351999
Log:
MFC r350520:
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/12/sys/netinet/sctp_output.c
Directory Properties:
stable/12/ (props changed)
Modified: stable/12/sys/netinet/sctp_output.c
==============================================================================
--- stable/12/sys/netinet/sctp_output.c Sat Sep 7 11:51:07 2019 (r351998)
+++ stable/12/sys/netinet/sctp_output.c Sat Sep 7 11:52:35 2019 (r351999)
@@ -4988,17 +4988,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))) {
@@ -5123,6 +5123,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
@@ -5131,7 +5132,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.
@@ -5151,6 +5152,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);
@@ -5186,37 +5188,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:
@@ -5239,6 +5259,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