diff options
author | cognet <cognet@FreeBSD.org> | 2003-06-17 00:31:30 +0000 |
---|---|---|
committer | cognet <cognet@FreeBSD.org> | 2003-06-17 00:31:30 +0000 |
commit | 74ee61c2bbc5044cd0c47d4e33abab739855286f (patch) | |
tree | f0827383c4c0a21900e79e2d828010faf18222c6 /sys/netinet6/in6_pcb.c | |
parent | 91eb81dd0ca9affe6de206f1624486f3dd7f458e (diff) | |
download | FreeBSD-src-74ee61c2bbc5044cd0c47d4e33abab739855286f.zip FreeBSD-src-74ee61c2bbc5044cd0c47d4e33abab739855286f.tar.gz |
Do not attempt to access to inp_socket fields if the socket is in the TIME_WAIT
state, as inp_socket will then be NULL. This fixes a panic that occurs when one
tries to bind a port that was previously binded with remaining TIME_WAIT
sockets.
Diffstat (limited to 'sys/netinet6/in6_pcb.c')
-rw-r--r-- | sys/netinet6/in6_pcb.c | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index b328d32..84ea6a9 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -198,12 +198,18 @@ in6_pcbbind(inp, nam, td) t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, lport, INPLOOKUP_WILDCARD); - if (t && + if (t && (t->inp_vflag & INP_TIMEWAIT)) { + if ((!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || + !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || + !(intotw(t)->tw_so_options & SO_REUSEPORT)) + && so->so_cred->cr_uid != + intotw(t)->tw_cred->cr_uid) + return (EADDRINUSE); + } else if (t && (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || - !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || - (t->inp_socket->so_options & - SO_REUSEPORT) == 0) && - (so->so_cred->cr_uid != + !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || + (t->inp_socket->so_options & SO_REUSEPORT) + == 0) && (so->so_cred->cr_uid != t->inp_socket->so_cred->cr_uid)) return (EADDRINUSE); if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && @@ -214,7 +220,17 @@ in6_pcbbind(inp, nam, td) t = in_pcblookup_local(pcbinfo, sin.sin_addr, lport, INPLOOKUP_WILDCARD); - if (t && + if (t && (t->inp_vflag & INP_TIMEWAIT)) { + if (so->so_cred->cr_uid != + intotw(t)->tw_cred->cr_uid && + (ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || + ((inp->inp_vflag & + INP_IPV6PROTO) == + (t->inp_vflag & + INP_IPV6PROTO)))) + return (EADDRINUSE); + } else if (t && (so->so_cred->cr_uid != t->inp_socket->so_cred->cr_uid) && (ntohl(t->inp_laddr.s_addr) != @@ -226,7 +242,9 @@ in6_pcbbind(inp, nam, td) } t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, lport, wild); - if (t && (reuseport & t->inp_socket->so_options) == 0) + if (t && (reuseport & ((t->inp_vflag & INP_TIMEWAIT) ? + intotw(t)->tw_so_options : + t->inp_socket->so_options)) == 0) return(EADDRINUSE); if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { @@ -235,12 +253,19 @@ in6_pcbbind(inp, nam, td) in6_sin6_2_sin(&sin, sin6); t = in_pcblookup_local(pcbinfo, sin.sin_addr, lport, wild); - if (t && - (reuseport & t->inp_socket->so_options) - == 0 && - (ntohl(t->inp_laddr.s_addr) - != INADDR_ANY || - INP_SOCKAF(so) == + if (t && t->inp_vflag & INP_TIMEWAIT) { + if ((reuseport & + intotw(t)->tw_so_options) == 0 && + (ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || ((inp->inp_vflag & + INP_IPV6PROTO) == + (t->inp_vflag & INP_IPV6PROTO)))) + return (EADDRINUSE); + } + else if (t && + (reuseport & t->inp_socket->so_options) + == 0 && (ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || INP_SOCKAF(so) == INP_SOCKAF(t->inp_socket))) return (EADDRINUSE); } |