Improve input validation for the IPPROTO_SCTP level socket options
SCTP_CONNECT_X and SCTP_CONNECT_X_DELAYED. Some issues where found by running syzkaller. MFC after: 3 days
This commit is contained in:
parent
051d65ce58
commit
568140500b
@ -1352,13 +1352,12 @@ static int
|
||||
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");
|
||||
@ -1397,17 +1396,12 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
|
||||
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
|
||||
|
@ -6391,30 +6391,33 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
|
||||
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);
|
||||
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);
|
||||
}
|
||||
(*num_v4) += 1;
|
||||
break;
|
||||
@ -6427,46 +6430,34 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
|
||||
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);
|
||||
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);
|
||||
}
|
||||
(*num_v6) += 1;
|
||||
break;
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -211,10 +211,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
|
||||
|
Loading…
Reference in New Issue
Block a user