Improve input validation for the IPPROTO_SCTP level socket options
SCTP_CONNECT_X and SCTP_CONNECT_X_DELAYED.
diff --git a/usrsctplib/netinet/sctp_usrreq.c b/usrsctplib/netinet/sctp_usrreq.c
index 9430d28..925fe09 100755
--- a/usrsctplib/netinet/sctp_usrreq.c
+++ b/usrsctplib/netinet/sctp_usrreq.c
@@ -34,7 +34,7 @@
#ifdef __FreeBSD__
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 345525 2019-03-26 08:27:00Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 347975 2019-05-19 17:28:00Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -1952,13 +1952,12 @@
sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
size_t optsize, void *p, int delay)
{
- int error = 0;
+ int error;
int creat_lock_on = 0;
struct sctp_tcb *stcb = NULL;
struct sockaddr *sa;
unsigned int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
uint32_t vrf_id;
- int bad_addresses = 0;
sctp_assoc_t *a_id;
SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
@@ -1997,17 +1996,12 @@
totaddrp = (unsigned int *)optval;
totaddr = *totaddrp;
sa = (struct sockaddr *)(totaddrp + 1);
- stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (unsigned int)(optsize - sizeof(int)), &bad_addresses);
- if ((stcb != NULL) || bad_addresses) {
+ error = sctp_connectx_helper_find(inp, sa, totaddr, &num_v4, &num_v6, (unsigned int)(optsize - sizeof(int)));
+ if (error != 0) {
/* Already have or am bring up an association */
SCTP_ASOC_CREATE_UNLOCK(inp);
creat_lock_on = 0;
- if (stcb)
- SCTP_TCB_UNLOCK(stcb);
- if (bad_addresses == 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- }
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
goto out_now;
}
#ifdef INET6
diff --git a/usrsctplib/netinet/sctputil.c b/usrsctplib/netinet/sctputil.c
index 4a8e944..a51e188 100755
--- a/usrsctplib/netinet/sctputil.c
+++ b/usrsctplib/netinet/sctputil.c
@@ -34,7 +34,7 @@
#ifdef __FreeBSD__
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 346134 2019-04-11 20:39:12Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctputil.c 347975 2019-05-19 17:28:00Z tuexen $");
#endif
#include <netinet/sctp_os.h>
@@ -7128,31 +7128,34 @@
return (added);
}
-struct sctp_tcb *
+int
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
- unsigned int *totaddr,
- unsigned int *num_v4, unsigned int *num_v6, int *error,
- unsigned int limit, int *bad_addr)
+ unsigned int totaddr,
+ unsigned int *num_v4, unsigned int *num_v6,
+ unsigned int limit)
{
struct sockaddr *sa;
- struct sctp_tcb *stcb = NULL;
+ struct sctp_tcb *stcb;
unsigned int incr, at, i;
at = 0;
sa = addr;
- *error = *num_v6 = *num_v4 = 0;
+ *num_v6 = *num_v4 = 0;
/* account and validate addresses */
- for (i = 0; i < *totaddr; i++) {
+ if (totaddr == 0) {
+ return (EINVAL);
+ }
+ for (i = 0; i < totaddr; i++) {
+ if (at + sizeof(struct sockaddr) > limit) {
+ return (EINVAL);
+ }
switch (sa->sa_family) {
#ifdef INET
case AF_INET:
incr = (unsigned int)sizeof(struct sockaddr_in);
#ifdef HAVE_SA_LEN
if (sa->sa_len != incr) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
+ return (EINVAL);
}
#endif
(*num_v4) += 1;
@@ -7166,18 +7169,12 @@
sin6 = (struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
/* Must be non-mapped for connectx */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
+ return (EINVAL);
}
incr = (unsigned int)sizeof(struct sockaddr_in6);
#ifdef HAVE_SA_LEN
if (sa->sa_len != incr) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
- *error = EINVAL;
- *bad_addr = 1;
- return (NULL);
+ return (EINVAL);
}
#endif
(*num_v6) += 1;
@@ -7185,29 +7182,23 @@
}
#endif
default:
- *totaddr = i;
- incr = 0;
- /* we are done */
- break;
+ return (EINVAL);
}
- if (i == *totaddr) {
- break;
+ if ((at + incr) > limit) {
+ return (EINVAL);
}
SCTP_INP_INCR_REF(inp);
stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
if (stcb != NULL) {
- /* Already have or am bring up an association */
- return (stcb);
+ SCTP_TCB_UNLOCK(stcb);
+ return (EALREADY);
} else {
SCTP_INP_DECR_REF(inp);
}
- if ((at + incr) > limit) {
- *totaddr = i;
- break;
- }
+ at += incr;
sa = (struct sockaddr *)((caddr_t)sa + incr);
}
- return ((struct sctp_tcb *)NULL);
+ return (0);
}
/*
diff --git a/usrsctplib/netinet/sctputil.h b/usrsctplib/netinet/sctputil.h
index f3a18be..92cb3ae 100755
--- a/usrsctplib/netinet/sctputil.h
+++ b/usrsctplib/netinet/sctputil.h
@@ -34,7 +34,7 @@
#ifdef __FreeBSD__
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 345467 2019-03-24 12:13:05Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctputil.h 347975 2019-05-19 17:28:00Z tuexen $");
#endif
#ifndef _NETINET_SCTP_UTIL_H_
@@ -223,10 +223,9 @@
int sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
int totaddr, int *error);
-struct sctp_tcb *
-sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
- unsigned int *totaddr, unsigned int *num_v4, unsigned int *num_v6,
- int *error, unsigned int limit, int *bad_addr);
+int
+sctp_connectx_helper_find(struct sctp_inpcb *, struct sockaddr *,
+ unsigned int, unsigned int *, unsigned int *, unsigned int);
int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *);
#ifdef INET6