Create new functions in_sockaddr(), in6_sockaddr(), and
in6_v4mapsin6_sockaddr() which allocate the appropriate sockaddr_in* structure and initialize it with the address and port information passed as arguments. Use calls to these new functions to replace code that is replicated multiple times in in_setsockaddr(), in_setpeeraddr(), in6_setsockaddr(), in6_setpeeraddr(), in6_mapped_sockaddr(), and in6_mapped_peeraddr(). Inline COMMON_END in tcp_usr_accept() so that we can call in_sockaddr() with temporary copies of the address and port after the PCB is unlocked. Fix the lock violation in tcp6_usr_accept() (caused by calling MALLOC() inside in6_mapped_peeraddr() while the PCB is locked) by changing the implementation of tcp6_usr_accept() to match tcp_usr_accept(). Reviewed by: suz
This commit is contained in:
parent
2d2341a634
commit
7199888e8f
@ -577,6 +577,23 @@ in_pcbdetach(inp)
|
||||
uma_zfree(ipi->ipi_zone, inp);
|
||||
}
|
||||
|
||||
struct sockaddr *
|
||||
in_sockaddr(port, addr_p)
|
||||
in_port_t port;
|
||||
struct in_addr *addr_p;
|
||||
{
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
|
||||
M_WAITOK | M_ZERO);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
sin->sin_addr = *addr_p;
|
||||
sin->sin_port = port;
|
||||
|
||||
return (struct sockaddr *)sin;
|
||||
}
|
||||
|
||||
/*
|
||||
* The wrapper function will pass down the pcbinfo for this function to lock.
|
||||
* The socket must have a valid
|
||||
@ -593,15 +610,8 @@ in_setsockaddr(so, nam, pcbinfo)
|
||||
{
|
||||
int s;
|
||||
register struct inpcb *inp;
|
||||
register struct sockaddr_in *sin;
|
||||
|
||||
/*
|
||||
* Do the malloc first in case it blocks.
|
||||
*/
|
||||
MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
|
||||
M_WAITOK | M_ZERO);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
struct in_addr addr;
|
||||
in_port_t port;
|
||||
|
||||
s = splnet();
|
||||
INP_INFO_RLOCK(pcbinfo);
|
||||
@ -609,17 +619,16 @@ in_setsockaddr(so, nam, pcbinfo)
|
||||
if (!inp) {
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
splx(s);
|
||||
free(sin, M_SONAME);
|
||||
return ECONNRESET;
|
||||
}
|
||||
INP_LOCK(inp);
|
||||
sin->sin_port = inp->inp_lport;
|
||||
sin->sin_addr = inp->inp_laddr;
|
||||
port = inp->inp_lport;
|
||||
addr = inp->inp_laddr;
|
||||
INP_UNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
splx(s);
|
||||
|
||||
*nam = (struct sockaddr *)sin;
|
||||
*nam = in_sockaddr(port, &addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -634,15 +643,8 @@ in_setpeeraddr(so, nam, pcbinfo)
|
||||
{
|
||||
int s;
|
||||
register struct inpcb *inp;
|
||||
register struct sockaddr_in *sin;
|
||||
|
||||
/*
|
||||
* Do the malloc first in case it blocks.
|
||||
*/
|
||||
MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
|
||||
M_WAITOK | M_ZERO);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
struct in_addr addr;
|
||||
in_port_t port;
|
||||
|
||||
s = splnet();
|
||||
INP_INFO_RLOCK(pcbinfo);
|
||||
@ -650,17 +652,16 @@ in_setpeeraddr(so, nam, pcbinfo)
|
||||
if (!inp) {
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
splx(s);
|
||||
free(sin, M_SONAME);
|
||||
return ECONNRESET;
|
||||
}
|
||||
INP_LOCK(inp);
|
||||
sin->sin_port = inp->inp_fport;
|
||||
sin->sin_addr = inp->inp_faddr;
|
||||
port = inp->inp_fport;
|
||||
addr = inp->inp_faddr;
|
||||
INP_UNLOCK(inp);
|
||||
INP_INFO_RUNLOCK(pcbinfo);
|
||||
splx(s);
|
||||
|
||||
*nam = (struct sockaddr *)sin;
|
||||
*nam = in_sockaddr(port, &addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -344,6 +344,8 @@ void in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr,
|
||||
void in_pcbrehash(struct inpcb *);
|
||||
int in_setpeeraddr(struct socket *so, struct sockaddr **nam, struct inpcbinfo *pcbinfo);
|
||||
int in_setsockaddr(struct socket *so, struct sockaddr **nam, struct inpcbinfo *pcbinfo);;
|
||||
struct sockaddr *
|
||||
in_sockaddr(in_port_t port, struct in_addr *addr);
|
||||
void in_pcbremlists(struct inpcb *inp);
|
||||
int prison_xinpcb(struct thread *td, struct inpcb *inp);
|
||||
#endif /* _KERNEL */
|
||||
|
@ -467,8 +467,8 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam)
|
||||
int error = 0;
|
||||
struct inpcb *inp = NULL;
|
||||
struct tcpcb *tp = NULL;
|
||||
struct sockaddr_in *sin;
|
||||
const int inirw = INI_READ;
|
||||
struct in_addr addr;
|
||||
in_port_t port = 0;
|
||||
TCPDEBUG0;
|
||||
|
||||
if (so->so_state & SS_ISDISCONNECTED) {
|
||||
@ -476,21 +476,12 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the malloc first in case it blocks.
|
||||
*/
|
||||
MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME,
|
||||
M_WAITOK | M_ZERO);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
|
||||
s = splnet();
|
||||
INP_INFO_RLOCK(&tcbinfo);
|
||||
inp = sotoinpcb(so);
|
||||
if (!inp) {
|
||||
INP_INFO_RUNLOCK(&tcbinfo);
|
||||
splx(s);
|
||||
free(sin, M_SONAME);
|
||||
return (EINVAL);
|
||||
}
|
||||
INP_LOCK(inp);
|
||||
@ -499,14 +490,20 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam)
|
||||
TCPDEBUG1();
|
||||
|
||||
/*
|
||||
* We inline in_setpeeraddr here, because we have already done
|
||||
* the locking and the malloc.
|
||||
* We inline in_setpeeraddr and COMMON_END here, so that we can
|
||||
* copy the data of interest and defer the malloc until after we
|
||||
* release the lock.
|
||||
*/
|
||||
sin->sin_port = inp->inp_fport;
|
||||
sin->sin_addr = inp->inp_faddr;
|
||||
*nam = (struct sockaddr *)sin;
|
||||
port = inp->inp_fport;
|
||||
addr = inp->inp_faddr;
|
||||
|
||||
COMMON_END(PRU_ACCEPT);
|
||||
out: TCPDEBUG2(PRU_ACCEPT);
|
||||
if (tp)
|
||||
INP_UNLOCK(inp);
|
||||
splx(s);
|
||||
if (error == 0)
|
||||
*nam = in_sockaddr(port, &addr);
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
@ -517,7 +514,10 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
|
||||
struct inpcb *inp = NULL;
|
||||
int error = 0;
|
||||
struct tcpcb *tp = NULL;
|
||||
const int inirw = INI_READ;
|
||||
struct in_addr addr;
|
||||
struct in6_addr addr6;
|
||||
in_port_t port = 0;
|
||||
int v4 = 0;
|
||||
TCPDEBUG0;
|
||||
|
||||
if (so->so_state & SS_ISDISCONNECTED) {
|
||||
@ -537,8 +537,31 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
|
||||
INP_INFO_RUNLOCK(&tcbinfo);
|
||||
tp = intotcpcb(inp);
|
||||
TCPDEBUG1();
|
||||
in6_mapped_peeraddr(so, nam);
|
||||
COMMON_END(PRU_ACCEPT);
|
||||
/*
|
||||
* We inline in6_mapped_peeraddr and COMMON_END here, so that we can
|
||||
* copy the data of interest and defer the malloc until after we
|
||||
* release the lock.
|
||||
*/
|
||||
if (inp->inp_vflag & INP_IPV4) {
|
||||
v4 = 1;
|
||||
port = inp->inp_fport;
|
||||
addr = inp->inp_faddr;
|
||||
} else {
|
||||
port = inp->inp_fport;
|
||||
addr6 = inp->in6p_faddr;
|
||||
}
|
||||
|
||||
out: TCPDEBUG2(PRU_ACCEPT);
|
||||
if (tp)
|
||||
INP_UNLOCK(inp);
|
||||
splx(s);
|
||||
if (error == 0) {
|
||||
if (v4)
|
||||
*nam = in6_v4mapsin6_sockaddr(port, &addr);
|
||||
else
|
||||
*nam = in6_sockaddr(port, &addr6);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
|
@ -626,6 +626,50 @@ in6_pcbdetach(inp)
|
||||
uma_zfree(ipi->ipi_zone, inp);
|
||||
}
|
||||
|
||||
struct sockaddr *
|
||||
in6_sockaddr(port, addr_p)
|
||||
in_port_t port;
|
||||
struct in6_addr *addr_p;
|
||||
{
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
|
||||
bzero(sin6, sizeof *sin6);
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_len = sizeof(*sin6);
|
||||
sin6->sin6_port = port;
|
||||
sin6->sin6_addr = *addr_p;
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
|
||||
else
|
||||
sin6->sin6_scope_id = 0; /*XXX*/
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_addr.s6_addr16[1] = 0;
|
||||
|
||||
return (struct sockaddr *)sin6;
|
||||
}
|
||||
|
||||
struct sockaddr *
|
||||
in6_v4mapsin6_sockaddr(port, addr_p)
|
||||
in_port_t port;
|
||||
struct in_addr *addr_p;
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 *sin6_p;
|
||||
|
||||
bzero(&sin, sizeof sin);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_port = port;
|
||||
sin.sin_addr = *addr_p;
|
||||
|
||||
MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME,
|
||||
M_WAITOK);
|
||||
in6_sin_2_v4mapsin6(&sin, sin6_p);
|
||||
|
||||
return (struct sockaddr *)sin6_p;
|
||||
}
|
||||
|
||||
/*
|
||||
* The calling convention of in6_setsockaddr() and in6_setpeeraddr() was
|
||||
* modified to match the pru_sockaddr() and pru_peeraddr() entry points
|
||||
@ -643,34 +687,20 @@ in6_setsockaddr(so, nam)
|
||||
{
|
||||
int s;
|
||||
register struct inpcb *inp;
|
||||
register struct sockaddr_in6 *sin6;
|
||||
|
||||
/*
|
||||
* Do the malloc first in case it blocks.
|
||||
*/
|
||||
MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
|
||||
bzero(sin6, sizeof *sin6);
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_len = sizeof(*sin6);
|
||||
struct in6_addr addr;
|
||||
in_port_t port;
|
||||
|
||||
s = splnet();
|
||||
inp = sotoinpcb(so);
|
||||
if (!inp) {
|
||||
splx(s);
|
||||
free(sin6, M_SONAME);
|
||||
return EINVAL;
|
||||
}
|
||||
sin6->sin6_port = inp->inp_lport;
|
||||
sin6->sin6_addr = inp->in6p_laddr;
|
||||
port = inp->inp_lport;
|
||||
addr = inp->in6p_laddr;
|
||||
splx(s);
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
|
||||
else
|
||||
sin6->sin6_scope_id = 0; /*XXX*/
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_addr.s6_addr16[1] = 0;
|
||||
|
||||
*nam = (struct sockaddr *)sin6;
|
||||
*nam = in6_sockaddr(port, &addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -681,34 +711,20 @@ in6_setpeeraddr(so, nam)
|
||||
{
|
||||
int s;
|
||||
struct inpcb *inp;
|
||||
register struct sockaddr_in6 *sin6;
|
||||
|
||||
/*
|
||||
* Do the malloc first in case it blocks.
|
||||
*/
|
||||
MALLOC(sin6, struct sockaddr_in6 *, sizeof(*sin6), M_SONAME, M_WAITOK);
|
||||
bzero((caddr_t)sin6, sizeof (*sin6));
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_len = sizeof(struct sockaddr_in6);
|
||||
struct in6_addr addr;
|
||||
in_port_t port;
|
||||
|
||||
s = splnet();
|
||||
inp = sotoinpcb(so);
|
||||
if (!inp) {
|
||||
splx(s);
|
||||
free(sin6, M_SONAME);
|
||||
return EINVAL;
|
||||
}
|
||||
sin6->sin6_port = inp->inp_fport;
|
||||
sin6->sin6_addr = inp->in6p_faddr;
|
||||
port = inp->inp_fport;
|
||||
addr = inp->in6p_faddr;
|
||||
splx(s);
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
|
||||
else
|
||||
sin6->sin6_scope_id = 0; /*XXX*/
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
|
||||
sin6->sin6_addr.s6_addr16[1] = 0;
|
||||
|
||||
*nam = (struct sockaddr *)sin6;
|
||||
*nam = in6_sockaddr(port, &addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,10 @@ void in6_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
|
||||
struct inpcb *(*)(struct inpcb *, int)));
|
||||
struct inpcb *
|
||||
in6_rtchange __P((struct inpcb *, int));
|
||||
struct sockaddr *
|
||||
in6_sockaddr __P((in_port_t port, struct in6_addr *addr_p));
|
||||
struct sockaddr *
|
||||
in6_v4mapsin6_sockaddr __P((in_port_t port, struct in_addr *addr_p));
|
||||
int in6_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
|
||||
int in6_setsockaddr __P((struct socket *so, struct sockaddr **nam));
|
||||
int in6_mapped_sockaddr __P((struct socket *so, struct sockaddr **nam));
|
||||
|
Loading…
Reference in New Issue
Block a user