Handle the case when calling the IPPROTO_SCTP level socket option

SCTP_STATUS on an association with no primary path (early state).

This issue was found by running syzkaller.

MFC after:		3 days
This commit is contained in:
Michael Tuexen 2019-03-02 14:15:33 +00:00
parent 8124c05f2c
commit 49f1449309
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=344723

View File

@ -2644,42 +2644,47 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
sstat->sstat_instrms = stcb->asoc.streamincnt;
sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
memcpy(&sstat->sstat_primary.spinfo_address,
&stcb->asoc.primary_destination->ro._l_addr,
((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
net = stcb->asoc.primary_destination;
((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
/*
* Again the user can get info from sctp_constants.h
* for what the state of the network is.
*/
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
/* It's unconfirmed */
sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
/* It's active */
sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
} else {
/* It's inactive */
sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
}
sstat->sstat_primary.spinfo_cwnd = net->cwnd;
sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
sstat->sstat_primary.spinfo_rto = net->RTO;
sstat->sstat_primary.spinfo_mtu = net->mtu;
switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
if (net != NULL) {
memcpy(&sstat->sstat_primary.spinfo_address,
&stcb->asoc.primary_destination->ro._l_addr,
((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
/*
* Again the user can get info from
* sctp_constants.h for what the state of
* the network is.
*/
if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
/* It's unconfirmed */
sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
/* It's active */
sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
} else {
/* It's inactive */
sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
}
sstat->sstat_primary.spinfo_cwnd = net->cwnd;
sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
sstat->sstat_primary.spinfo_rto = net->RTO;
sstat->sstat_primary.spinfo_mtu = net->mtu;
switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
#if defined(INET)
case AF_INET:
sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
break;
case AF_INET:
sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
break;
#endif
#if defined(INET6)
case AF_INET6:
sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD;
break;
case AF_INET6:
sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD;
break;
#endif
default:
break;
default:
break;
}
} else {
memset(&sstat->sstat_primary, 0, sizeof(struct sctp_paddrinfo));
}
sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);