mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 01:30:30 -04:00
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. MFC after: 3 days
This commit is contained in:
parent
fbe12f2085
commit
bedf9eb987
1 changed files with 47 additions and 26 deletions
|
|
@ -4988,17 +4988,17 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
|||
*/
|
||||
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_initpkt,
|
|||
*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_initpkt,
|
|||
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_initpkt,
|
|||
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_initpkt,
|
|||
#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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue