- sctputil.c - If debug is on, the INPKILL timer can deref a freed value.
Change so that we save off a type field for display and NULL inp just for good measure. - sctp_output.c - Fix it so in sending to the loopback we use the src address of the inbound INIT. We don't want to do this for non local addresses since otherwise we might be ingressed filtered so we need to use the best src address and list the address sent to. Obtained from: time bug - Neil Wilson MFC after: 1 week
This commit is contained in:
parent
bcbd871a3f
commit
d61374e183
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179180
@ -2217,15 +2217,6 @@ sctp_is_ifa_addr_preferred(struct sctp_ifa *ifa,
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:1\n");
|
||||
return (NULL);
|
||||
}
|
||||
if (ifa->src_is_priv && ifa->src_is_loop) {
|
||||
/*
|
||||
* don't allow fe80::1 to be a src on loop ::1, we
|
||||
* don't list it to the peer so we will get an
|
||||
* abort.
|
||||
*/
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:2a\n");
|
||||
return (NULL);
|
||||
}
|
||||
if (ifa->src_is_priv && !ifa->src_is_loop) {
|
||||
if (dest_is_loop) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:2\n");
|
||||
@ -2689,6 +2680,16 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn,
|
||||
if (sifa == NULL)
|
||||
continue;
|
||||
#ifdef INET6
|
||||
if (fam == AF_INET6 &&
|
||||
dest_is_loop &&
|
||||
sifa->src_is_loop && sifa->src_is_priv) {
|
||||
/*
|
||||
* don't allow fe80::1 to be a src on loop ::1, we
|
||||
* don't list it to the peer so we will get an
|
||||
* abort.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (fam == AF_INET6 &&
|
||||
IN6_IS_ADDR_LINKLOCAL(&sifa->address.sin6.sin6_addr) &&
|
||||
IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
|
||||
@ -2701,13 +2702,6 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn,
|
||||
if (sin6.sin6_scope_id != lsa6.sin6_scope_id) {
|
||||
continue;
|
||||
}
|
||||
if (dest_is_loop) {
|
||||
/*
|
||||
* we don't give out fe80::1, we must use
|
||||
* ::1
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
@ -3412,10 +3406,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
struct sctp_tmit_chunk *chk,
|
||||
int out_of_asoc_ok,
|
||||
uint16_t port,
|
||||
int so_locked
|
||||
int so_locked,
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
#endif
|
||||
union sctp_sockstore *over_addr
|
||||
)
|
||||
/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */
|
||||
{
|
||||
@ -3575,17 +3570,22 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
}
|
||||
ip->ip_src = net->ro._s_addr->address.sin.sin_addr;
|
||||
} else {
|
||||
struct sctp_ifa *_lsrc;
|
||||
if (over_addr == NULL) {
|
||||
struct sctp_ifa *_lsrc;
|
||||
|
||||
_lsrc = sctp_source_address_selection(inp, stcb, ro,
|
||||
net,
|
||||
out_of_asoc_ok,
|
||||
vrf_id);
|
||||
if (_lsrc == NULL) {
|
||||
goto no_route;
|
||||
_lsrc = sctp_source_address_selection(inp, stcb, ro,
|
||||
net,
|
||||
out_of_asoc_ok,
|
||||
vrf_id);
|
||||
if (_lsrc == NULL) {
|
||||
goto no_route;
|
||||
}
|
||||
ip->ip_src = _lsrc->address.sin.sin_addr;
|
||||
sctp_free_ifa(_lsrc);
|
||||
} else {
|
||||
ip->ip_src = over_addr->sin.sin_addr;
|
||||
SCTP_RTALLOC((&ro->ro_rt), vrf_id);
|
||||
}
|
||||
ip->ip_src = _lsrc->address.sin.sin_addr;
|
||||
sctp_free_ifa(_lsrc);
|
||||
}
|
||||
if (port) {
|
||||
udp = (struct udphdr *)(ip + 1);
|
||||
@ -3879,28 +3879,33 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
}
|
||||
lsa6->sin6_addr = net->ro._s_addr->address.sin6.sin6_addr;
|
||||
} else {
|
||||
struct sctp_ifa *_lsrc;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)&ro->ro_dst;
|
||||
/* KAME hack: embed scopeid */
|
||||
if (sa6_embedscope(sin6, ip6_use_defzone) != 0) {
|
||||
SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
_lsrc = sctp_source_address_selection(inp, stcb, ro,
|
||||
net,
|
||||
out_of_asoc_ok,
|
||||
vrf_id);
|
||||
(void)sa6_recoverscope(sin6);
|
||||
if (_lsrc == NULL) {
|
||||
goto no_route;
|
||||
if (over_addr == NULL) {
|
||||
struct sctp_ifa *_lsrc;
|
||||
|
||||
_lsrc = sctp_source_address_selection(inp, stcb, ro,
|
||||
net,
|
||||
out_of_asoc_ok,
|
||||
vrf_id);
|
||||
if (_lsrc == NULL) {
|
||||
goto no_route;
|
||||
}
|
||||
lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr;
|
||||
sctp_free_ifa(_lsrc);
|
||||
} else {
|
||||
lsa6->sin6_addr = over_addr->sin6.sin6_addr;
|
||||
SCTP_RTALLOC((&ro->ro_rt), vrf_id);
|
||||
}
|
||||
lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr;
|
||||
sctp_free_ifa(_lsrc);
|
||||
(void)sa6_recoverscope(sin6);
|
||||
}
|
||||
lsa6->sin6_port = inp->sctp_lport;
|
||||
|
||||
if ((ro->ro_rt == NULL)) {
|
||||
if (ro->ro_rt == NULL) {
|
||||
/*
|
||||
* src addr selection failed to find a route (or
|
||||
* valid source addr), so we can't get there from
|
||||
@ -4322,7 +4327,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n");
|
||||
ret = sctp_lowlevel_chunk_output(inp, stcb, net,
|
||||
(struct sockaddr *)&net->ro._l_addr,
|
||||
m, 0, NULL, 0, 0, NULL, 0, net->port, so_locked);
|
||||
m, 0, NULL, 0, 0, NULL, 0, net->port, so_locked, NULL);
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret);
|
||||
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
|
||||
@ -4849,14 +4854,13 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
struct sctp_prsctp_supported_param *prsctp;
|
||||
struct sctp_ecn_nonce_supported_param *ecn_nonce;
|
||||
struct sctp_supported_chunk_types_param *pr_supported;
|
||||
struct sockaddr_storage store;
|
||||
struct sockaddr_in *sin;
|
||||
union sctp_sockstore store, store1, *over_addr;
|
||||
struct sockaddr_in *sin, *to_sin;
|
||||
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 *sin6;
|
||||
struct sockaddr_in6 *sin6, *to_sin6;
|
||||
|
||||
#endif
|
||||
sctp_route_t *ro;
|
||||
struct ip *iph;
|
||||
|
||||
#ifdef INET6
|
||||
@ -4896,6 +4900,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
(offset + sizeof(struct sctp_init_chunk)),
|
||||
&abort_flag, (struct sctp_chunkhdr *)init_chk);
|
||||
if (abort_flag) {
|
||||
do_a_abort:
|
||||
sctp_send_abort(init_pkt, iphlen, sh,
|
||||
init_chk->init.initiate_tag, op_err, vrf_id, port);
|
||||
return;
|
||||
@ -4961,19 +4966,42 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
#endif
|
||||
/* now for scope setup */
|
||||
memset((caddr_t)&store, 0, sizeof(store));
|
||||
sin = (struct sockaddr_in *)&store;
|
||||
memset((caddr_t)&store1, 0, sizeof(store1));
|
||||
sin = &store.sin;
|
||||
to_sin = &store1.sin;
|
||||
#ifdef INET6
|
||||
sin6 = (struct sockaddr_in6 *)&store;
|
||||
sin6 = &store.sin6;
|
||||
to_sin6 = &store1.sin6;
|
||||
#endif
|
||||
iph = mtod(init_pkt, struct ip *);
|
||||
/* establish the to_addr's */
|
||||
switch (iph->ip_v) {
|
||||
case IPVERSION:
|
||||
to_sin->sin_port = sh->dest_port;
|
||||
to_sin->sin_family = AF_INET;
|
||||
to_sin->sin_len = sizeof(struct sockaddr_in);
|
||||
to_sin->sin_addr = iph->ip_dst;
|
||||
break;
|
||||
#ifdef INET6
|
||||
case IPV6_VERSION >> 4:
|
||||
ip6 = mtod(init_pkt, struct ip6_hdr *);
|
||||
to_sin6->sin6_addr = ip6->ip6_dst;
|
||||
to_sin6->sin6_scope_id = 0;
|
||||
to_sin6->sin6_port = sh->dest_port;
|
||||
to_sin6->sin6_family = AF_INET6;
|
||||
to_sin6->sin6_len = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto do_a_abort;
|
||||
break;
|
||||
};
|
||||
|
||||
if (net == NULL) {
|
||||
to = (struct sockaddr *)&store;
|
||||
iph = mtod(init_pkt, struct ip *);
|
||||
switch (iph->ip_v) {
|
||||
case IPVERSION:
|
||||
{
|
||||
struct sctp_ifa *addr;
|
||||
sctp_route_t iproute;
|
||||
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_len = sizeof(struct sockaddr_in);
|
||||
sin->sin_port = sh->src_port;
|
||||
@ -4985,20 +5013,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
stc.address[3] = 0;
|
||||
stc.addr_type = SCTP_IPV4_ADDRESS;
|
||||
/* local from address */
|
||||
memset(&iproute, 0, sizeof(iproute));
|
||||
ro = &iproute;
|
||||
memcpy(&ro->ro_dst, sin, sizeof(*sin));
|
||||
addr = sctp_source_address_selection(inp, NULL,
|
||||
ro, NULL, 0,
|
||||
vrf_id);
|
||||
if (addr == NULL)
|
||||
return;
|
||||
|
||||
if (ro->ro_rt) {
|
||||
RTFREE(ro->ro_rt);
|
||||
ro->ro_rt = NULL;
|
||||
}
|
||||
stc.laddress[0] = addr->address.sin.sin_addr.s_addr;
|
||||
stc.laddress[0] = to_sin->sin_addr.s_addr;
|
||||
stc.laddress[1] = 0;
|
||||
stc.laddress[2] = 0;
|
||||
stc.laddress[3] = 0;
|
||||
@ -5019,15 +5034,11 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
stc.site_scope = 1;
|
||||
stc.local_scope = 0;
|
||||
}
|
||||
sctp_free_ifa(addr);
|
||||
break;
|
||||
}
|
||||
#ifdef INET6
|
||||
case IPV6_VERSION >> 4:
|
||||
{
|
||||
struct sctp_ifa *addr;
|
||||
struct route_in6 iproute6;
|
||||
|
||||
ip6 = mtod(init_pkt, struct ip6_hdr *);
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_len = sizeof(struct sockaddr_in6);
|
||||
@ -5091,27 +5102,14 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
*/
|
||||
stc.site_scope = 1;
|
||||
}
|
||||
/* local from address */
|
||||
memset(&iproute6, 0, sizeof(iproute6));
|
||||
ro = (sctp_route_t *) & iproute6;
|
||||
memcpy(&ro->ro_dst, sin6, sizeof(*sin6));
|
||||
addr = sctp_source_address_selection(inp, NULL,
|
||||
ro, NULL, 0, vrf_id);
|
||||
if (addr == NULL)
|
||||
return;
|
||||
|
||||
if (ro->ro_rt) {
|
||||
RTFREE(ro->ro_rt);
|
||||
ro->ro_rt = NULL;
|
||||
}
|
||||
memcpy(&stc.laddress, &addr->address.sin6.sin6_addr, sizeof(struct in6_addr));
|
||||
memcpy(&stc.laddress, &to_sin6->sin6_addr, sizeof(struct in6_addr));
|
||||
stc.laddr_type = SCTP_IPV6_ADDRESS;
|
||||
sctp_free_ifa(addr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
/* TSNH */
|
||||
goto do_a_abort;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -5493,8 +5491,15 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
}
|
||||
p_len += padval;
|
||||
}
|
||||
if (stc.loopback_scope) {
|
||||
over_addr = &store1;
|
||||
} else {
|
||||
over_addr = NULL;
|
||||
|
||||
}
|
||||
|
||||
(void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0,
|
||||
NULL, 0, port, SCTP_SO_NOT_LOCKED);
|
||||
NULL, 0, port, SCTP_SO_NOT_LOCKED, over_addr);
|
||||
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
|
||||
}
|
||||
|
||||
@ -7651,7 +7656,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
|
||||
(struct sockaddr *)&net->ro._l_addr,
|
||||
outchain, auth_offset, auth,
|
||||
no_fragmentflg, 0, NULL, asconf, net->port, so_locked))) {
|
||||
no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) {
|
||||
if (error == ENOBUFS) {
|
||||
asoc->ifp_had_enobuf = 1;
|
||||
SCTP_STAT_INCR(sctps_lowlevelerr);
|
||||
@ -7878,7 +7883,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
|
||||
(struct sockaddr *)&net->ro._l_addr,
|
||||
outchain, auth_offset, auth,
|
||||
no_fragmentflg, 0, NULL, asconf, net->port, so_locked))) {
|
||||
no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) {
|
||||
if (error == ENOBUFS) {
|
||||
asoc->ifp_had_enobuf = 1;
|
||||
SCTP_STAT_INCR(sctps_lowlevelerr);
|
||||
@ -8167,7 +8172,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
no_fragmentflg,
|
||||
bundle_at,
|
||||
data_list[0],
|
||||
asconf, net->port, so_locked))) {
|
||||
asconf, net->port, so_locked, NULL))) {
|
||||
/* error, we could not output */
|
||||
if (error == ENOBUFS) {
|
||||
SCTP_STAT_INCR(sctps_lowlevelerr);
|
||||
@ -8881,7 +8886,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
|
||||
|
||||
if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo,
|
||||
(struct sockaddr *)&chk->whoTo->ro._l_addr, m, auth_offset,
|
||||
auth, no_fragmentflg, 0, NULL, 0, chk->whoTo->port, so_locked))) {
|
||||
auth, no_fragmentflg, 0, NULL, 0, chk->whoTo->port, so_locked, NULL))) {
|
||||
SCTP_STAT_INCR(sctps_lowlevelerr);
|
||||
return (error);
|
||||
}
|
||||
@ -9119,7 +9124,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
|
||||
/* Now lets send it, if there is anything to send :> */
|
||||
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
|
||||
(struct sockaddr *)&net->ro._l_addr, m, auth_offset,
|
||||
auth, no_fragmentflg, 0, NULL, 0, net->port, so_locked))) {
|
||||
auth, no_fragmentflg, 0, NULL, 0, net->port, so_locked, NULL))) {
|
||||
/* error, we could not output */
|
||||
SCTP_STAT_INCR(sctps_lowlevelerr);
|
||||
return (error);
|
||||
@ -10099,7 +10104,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
|
||||
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination,
|
||||
(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr,
|
||||
m_out, auth_offset, auth, 1, 0, NULL, 0, stcb->asoc.primary_destination->port, so_locked);
|
||||
m_out, auth_offset, auth, 1, 0, NULL, 0, stcb->asoc.primary_destination->port, so_locked, NULL);
|
||||
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
|
||||
}
|
||||
|
||||
@ -10128,7 +10133,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
|
||||
SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_msg);
|
||||
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
|
||||
(struct sockaddr *)&net->ro._l_addr,
|
||||
m_shutdown_comp, 0, NULL, 1, 0, NULL, 0, net->port, SCTP_SO_NOT_LOCKED);
|
||||
m_shutdown_comp, 0, NULL, 1, 0, NULL, 0, net->port, SCTP_SO_NOT_LOCKED, NULL);
|
||||
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
|
||||
return;
|
||||
}
|
||||
|
@ -1420,7 +1420,7 @@ sctp_timeout_handler(void *t)
|
||||
struct socket *so;
|
||||
|
||||
#endif
|
||||
int did_output;
|
||||
int did_output, type;
|
||||
struct sctp_iterator *it = NULL;
|
||||
|
||||
tmr = (struct sctp_timer *)t;
|
||||
@ -1460,6 +1460,7 @@ sctp_timeout_handler(void *t)
|
||||
it = (struct sctp_iterator *)inp;
|
||||
inp = NULL;
|
||||
}
|
||||
type = tmr->type;
|
||||
if (inp) {
|
||||
SCTP_INP_INCR_REF(inp);
|
||||
if ((inp->sctp_socket == 0) &&
|
||||
@ -1838,6 +1839,7 @@ sctp_timeout_handler(void *t)
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_3);
|
||||
sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
|
||||
SCTP_CALLED_DIRECTLY_NOCMPSET);
|
||||
inp = NULL;
|
||||
goto out_no_decr;
|
||||
default:
|
||||
SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n",
|
||||
@ -1869,9 +1871,7 @@ sctp_timeout_handler(void *t)
|
||||
}
|
||||
out_no_decr:
|
||||
SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type %d)\n",
|
||||
tmr->type);
|
||||
if (inp) {
|
||||
}
|
||||
type);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user