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, &params, 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