svn commit: r353410 - releng/12.1/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Thu Oct 10 18:19:24 UTC 2019
Author: tuexen
Date: Thu Oct 10 18:19:22 2019
New Revision: 353410
URL: https://svnweb.freebsd.org/changeset/base/353410
Log:
MFS r353395:
Add missing input validation. This could result in reading from
uninitialized memory.
The issue was found by OSS-Fuzz for usrsctp and reported in
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=17780
MFS r353396:
Cleanup sctp_asconf_error_response() and ensure that the parameter
is padded as required. This fixes the followig bug reported by
OSS-Fuzz for the usersctp stack:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=17790
MFS r353397:
When skipping the address parameter, take the padding into account.
MFS r353398:
Fix the adding of padding to COOKIE-ECHO chunks.
Thanks to Mark Wodrich who found this issue while fuzz testing the
usrsctp stack and reported the issue in
https://github.com/sctplab/usrsctp/issues/382
MFS r353399:
Plumb an mbuf leak found by Mark Wodrich from Google by fuzz testing the
userland stack and reporting it in:
https://github.com/sctplab/usrsctp/issues/396
MFS r353400:
Fix a use after free bug when removing remote addresses.
This bug was found by OSS-Fuzz and reported in
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=18004
MFS r353401:
Plumb an mbuf leak in a code path that should not be taken. Also avoid
that this path is taken by setting the tail pointer correctly.
There is still bug related to handling unordered unfragmented messages
which were delayed in deferred handling.
This issue was found by OSS-Fuzz testing the usrsctp stack and reported
in
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=17794
MFS r353403:
Validate length before use it, not vice versa.
r353060 should have contained this...
This fixes
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=18070
Approved by: re (gjb@)
Modified:
releng/12.1/sys/netinet/sctp_asconf.c
releng/12.1/sys/netinet/sctp_indata.c
releng/12.1/sys/netinet/sctp_input.c
releng/12.1/sys/netinet/sctp_output.c
Directory Properties:
releng/12.1/ (props changed)
Modified: releng/12.1/sys/netinet/sctp_asconf.c
==============================================================================
--- releng/12.1/sys/netinet/sctp_asconf.c Thu Oct 10 17:29:47 2019 (r353409)
+++ releng/12.1/sys/netinet/sctp_asconf.c Thu Oct 10 18:19:22 2019 (r353410)
@@ -105,42 +105,47 @@ sctp_asconf_error_response(uint32_t id, uint16_t cause
struct mbuf *m_reply = NULL;
struct sctp_asconf_paramhdr *aph;
struct sctp_error_cause *error;
+ size_t buf_len;
+ uint16_t i, param_length, cause_length, padding_length;
uint8_t *tlv;
- m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) +
- tlv_length +
- sizeof(struct sctp_error_cause)),
- 0, M_NOWAIT, 1, MT_DATA);
+ if (error_tlv == NULL) {
+ tlv_length = 0;
+ }
+ cause_length = sizeof(struct sctp_error_cause) + tlv_length;
+ param_length = sizeof(struct sctp_asconf_paramhdr) + cause_length;
+ padding_length = tlv_length % 4;
+ if (padding_length != 0) {
+ padding_length = 4 - padding_length;
+ }
+ buf_len = param_length + padding_length;
+ if (buf_len > MLEN) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1,
+ "asconf_error_response: tlv_length (%xh) too big\n",
+ tlv_length);
+ return (NULL);
+ }
+ m_reply = sctp_get_mbuf_for_msg(buf_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_reply == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1,
"asconf_error_response: couldn't get mbuf!\n");
return (NULL);
}
aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
- error = (struct sctp_error_cause *)(aph + 1);
-
- aph->correlation_id = id;
aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
+ aph->ph.param_length = htons(param_length);
+ aph->correlation_id = id;
+ error = (struct sctp_error_cause *)(aph + 1);
error->code = htons(cause);
- error->length = tlv_length + sizeof(struct sctp_error_cause);
- aph->ph.param_length = error->length +
- sizeof(struct sctp_asconf_paramhdr);
-
- if (aph->ph.param_length > MLEN) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_error_response: tlv_length (%xh) too big\n",
- tlv_length);
- sctp_m_freem(m_reply); /* discard */
- return (NULL);
- }
+ error->length = htons(cause_length);
if (error_tlv != NULL) {
tlv = (uint8_t *)(error + 1);
memcpy(tlv, error_tlv, tlv_length);
+ for (i = 0; i < padding_length; i++) {
+ tlv[tlv_length + i] = 0;
+ }
}
- SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
- error->length = htons(error->length);
- aph->ph.param_length = htons(aph->ph.param_length);
-
+ SCTP_BUF_LEN(m_reply) = buf_len;
return (m_reply);
}
@@ -169,10 +174,16 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struc
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -272,7 +283,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struc
static int
sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
{
- struct sctp_nets *src_net, *net;
+ struct sctp_nets *src_net, *net, *nnet;
/* make sure the source address exists as a destination net */
src_net = sctp_findnet(stcb, src);
@@ -282,10 +293,9 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *s
}
/* delete all destination addresses except the source */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) {
if (net != src_net) {
/* delete this address */
- sctp_remove_net(stcb, net);
SCTPDBG(SCTP_DEBUG_ASCONF1,
"asconf_del_remote_addrs_except: deleting ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1,
@@ -293,6 +303,7 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *s
/* notify upper layer */
sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
(struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
+ sctp_remove_net(stcb, net);
}
}
return (0);
@@ -323,10 +334,16 @@ sctp_process_asconf_delete_ip(struct sockaddr *src,
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -454,10 +471,16 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
#endif
aparam_length = ntohs(aph->ph.param_length);
+ if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
+ return (NULL);
+ }
ph = (struct sctp_paramhdr *)(aph + 1);
param_type = ntohs(ph->param_type);
#if defined(INET) || defined(INET6)
param_length = ntohs(ph->param_length);
+ if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
+ return (NULL);
+ }
#endif
sa = &store.sa;
switch (param_type) {
@@ -676,8 +699,8 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset
sctp_m_freem(m_ack);
return;
}
- /* param_length is already validated in process_control... */
- offset += ntohs(p_addr->ph.param_length); /* skip lookup addr */
+ /* skip lookup addr */
+ offset += SCTP_SIZE32(ntohs(p_addr->ph.param_length));
/* get pointer to first asconf param in ASCONF */
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf);
if (aph == NULL) {
@@ -762,8 +785,6 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset
if (m_result != NULL) {
SCTP_BUF_NEXT(m_tail) = m_result;
m_tail = m_result;
- /* update lengths, make sure it's aligned too */
- SCTP_BUF_LEN(m_result) = SCTP_SIZE32(SCTP_BUF_LEN(m_result));
ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result);
/* set flag to force success reports */
error = 1;
Modified: releng/12.1/sys/netinet/sctp_indata.c
==============================================================================
--- releng/12.1/sys/netinet/sctp_indata.c Thu Oct 10 17:29:47 2019 (r353409)
+++ releng/12.1/sys/netinet/sctp_indata.c Thu Oct 10 18:19:22 2019 (r353410)
@@ -716,6 +716,7 @@ sctp_add_to_tail_pointer(struct sctp_queued_to_read *c
}
if (control->tail_mbuf == NULL) {
/* TSNH */
+ sctp_m_freem(control->data);
control->data = m;
sctp_setup_tail_pointer(control);
return;
@@ -2119,10 +2120,13 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struc
struct mbuf *mm;
control->data = dmbuf;
+ control->tail_mbuf = NULL;
for (mm = control->data; mm; mm = mm->m_next) {
control->length += SCTP_BUF_LEN(mm);
+ if (SCTP_BUF_NEXT(mm) == NULL) {
+ control->tail_mbuf = mm;
+ }
}
- control->tail_mbuf = NULL;
control->end_added = 1;
control->last_frag_seen = 1;
control->first_frag_seen = 1;
Modified: releng/12.1/sys/netinet/sctp_input.c
==============================================================================
--- releng/12.1/sys/netinet/sctp_input.c Thu Oct 10 17:29:47 2019 (r353409)
+++ releng/12.1/sys/netinet/sctp_input.c Thu Oct 10 18:19:22 2019 (r353410)
@@ -465,6 +465,10 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int
if (!cookie_found) {
uint16_t len;
+ /* Only report the missing cookie parameter */
+ if (op_err != NULL) {
+ sctp_m_freem(op_err);
+ }
len = (uint16_t)(sizeof(struct sctp_error_missing_param) + sizeof(uint16_t));
/* We abort with an error of missing mandatory param */
op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
Modified: releng/12.1/sys/netinet/sctp_output.c
==============================================================================
--- releng/12.1/sys/netinet/sctp_output.c Thu Oct 10 17:29:47 2019 (r353409)
+++ releng/12.1/sys/netinet/sctp_output.c Thu Oct 10 18:19:22 2019 (r353410)
@@ -9059,8 +9059,7 @@ sctp_send_cookie_echo(struct mbuf *m,
pad = 4 - pad;
}
if (pad > 0) {
- cookie = sctp_pad_lastmbuf(cookie, pad, NULL);
- if (cookie == NULL) {
+ if (sctp_pad_lastmbuf(cookie, pad, NULL) == NULL) {
return (-8);
}
}
More information about the svn-src-all
mailing list