netinet6: require network epoch for in6_pcbconnect()
This removes recursive epoch entry in the syncache case. Fixes unprotected access to V_in6_ifaddrhead in in6_pcbladdr(), as well as access to prison IP address lists. It also matches what IPv4 in_pcbconnect() does. Reviewed by: markj Differential revision: https://reviews.freebsd.org/D38355
This commit is contained in:
parent
221b9e3d06
commit
3d76be28ec
@ -1471,13 +1471,16 @@ static int
|
|||||||
tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
||||||
{
|
{
|
||||||
struct inpcb *inp = tptoinpcb(tp);
|
struct inpcb *inp = tptoinpcb(tp);
|
||||||
|
struct epoch_tracker et;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
INP_WLOCK_ASSERT(inp);
|
INP_WLOCK_ASSERT(inp);
|
||||||
|
|
||||||
|
NET_EPOCH_ENTER(et);
|
||||||
INP_HASH_WLOCK(&V_tcbinfo);
|
INP_HASH_WLOCK(&V_tcbinfo);
|
||||||
error = in6_pcbconnect(inp, nam, td->td_ucred, true);
|
error = in6_pcbconnect(inp, nam, td->td_ucred, true);
|
||||||
INP_HASH_WUNLOCK(&V_tcbinfo);
|
INP_HASH_WUNLOCK(&V_tcbinfo);
|
||||||
|
NET_EPOCH_EXIT(et);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
|
@ -357,8 +357,8 @@ in6_pcbladdr(struct inpcb *inp, struct sockaddr_in6 *sin6,
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
int scope_ambiguous = 0;
|
int scope_ambiguous = 0;
|
||||||
struct in6_addr in6a;
|
struct in6_addr in6a;
|
||||||
struct epoch_tracker et;
|
|
||||||
|
|
||||||
|
NET_EPOCH_ASSERT();
|
||||||
INP_WLOCK_ASSERT(inp);
|
INP_WLOCK_ASSERT(inp);
|
||||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); /* XXXRW: why? */
|
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); /* XXXRW: why? */
|
||||||
|
|
||||||
@ -381,10 +381,8 @@ in6_pcbladdr(struct inpcb *inp, struct sockaddr_in6 *sin6,
|
|||||||
if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0)
|
if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
NET_EPOCH_ENTER(et);
|
|
||||||
error = in6_selectsrc_socket(sin6, inp->in6p_outputopts,
|
error = in6_selectsrc_socket(sin6, inp->in6p_outputopts,
|
||||||
inp, inp->inp_cred, scope_ambiguous, &in6a, NULL);
|
inp, inp->inp_cred, scope_ambiguous, &in6a, NULL);
|
||||||
NET_EPOCH_EXIT(et);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
@ -422,6 +420,9 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred,
|
|||||||
struct sockaddr_in6 laddr6;
|
struct sockaddr_in6 laddr6;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
NET_EPOCH_ASSERT();
|
||||||
|
INP_WLOCK_ASSERT(inp);
|
||||||
|
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
||||||
KASSERT(sin6->sin6_family == AF_INET6,
|
KASSERT(sin6->sin6_family == AF_INET6,
|
||||||
("%s: invalid address family for %p", __func__, sin6));
|
("%s: invalid address family for %p", __func__, sin6));
|
||||||
KASSERT(sin6->sin6_len == sizeof(*sin6),
|
KASSERT(sin6->sin6_len == sizeof(*sin6),
|
||||||
@ -430,9 +431,6 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred,
|
|||||||
bzero(&laddr6, sizeof(laddr6));
|
bzero(&laddr6, sizeof(laddr6));
|
||||||
laddr6.sin6_family = AF_INET6;
|
laddr6.sin6_family = AF_INET6;
|
||||||
|
|
||||||
INP_WLOCK_ASSERT(inp);
|
|
||||||
INP_HASH_WLOCK_ASSERT(pcbinfo);
|
|
||||||
|
|
||||||
#ifdef ROUTE_MPATH
|
#ifdef ROUTE_MPATH
|
||||||
if (CALC_FLOWID_OUTBOUND) {
|
if (CALC_FLOWID_OUTBOUND) {
|
||||||
uint32_t hash_type, hash_val;
|
uint32_t hash_type, hash_val;
|
||||||
|
@ -1101,9 +1101,7 @@ udp6_close(struct socket *so)
|
|||||||
static int
|
static int
|
||||||
udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||||
{
|
{
|
||||||
#ifdef INET
|
|
||||||
struct epoch_tracker et;
|
struct epoch_tracker et;
|
||||||
#endif
|
|
||||||
struct inpcb *inp;
|
struct inpcb *inp;
|
||||||
struct inpcbinfo *pcbinfo;
|
struct inpcbinfo *pcbinfo;
|
||||||
struct sockaddr_in6 *sin6;
|
struct sockaddr_in6 *sin6;
|
||||||
@ -1181,9 +1179,11 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||||||
vflagsav = inp->inp_vflag;
|
vflagsav = inp->inp_vflag;
|
||||||
inp->inp_vflag &= ~INP_IPV4;
|
inp->inp_vflag &= ~INP_IPV4;
|
||||||
inp->inp_vflag |= INP_IPV6;
|
inp->inp_vflag |= INP_IPV6;
|
||||||
|
NET_EPOCH_ENTER(et);
|
||||||
INP_HASH_WLOCK(pcbinfo);
|
INP_HASH_WLOCK(pcbinfo);
|
||||||
error = in6_pcbconnect(inp, nam, td->td_ucred, true);
|
error = in6_pcbconnect(inp, nam, td->td_ucred, true);
|
||||||
INP_HASH_WUNLOCK(pcbinfo);
|
INP_HASH_WUNLOCK(pcbinfo);
|
||||||
|
NET_EPOCH_EXIT(et);
|
||||||
/*
|
/*
|
||||||
* If connect succeeds, mark socket as connected. If
|
* If connect succeeds, mark socket as connected. If
|
||||||
* connect fails and socket is unbound, reset inp_vflag
|
* connect fails and socket is unbound, reset inp_vflag
|
||||||
|
Loading…
Reference in New Issue
Block a user