svn commit: r227428 - in stable/9/sys: netinet netinet6
Mikolaj Golub
trociny at FreeBSD.org
Thu Nov 10 20:28:31 UTC 2011
Author: trociny
Date: Thu Nov 10 20:28:30 2011
New Revision: 227428
URL: http://svn.freebsd.org/changeset/base/227428
Log:
MFC r227204, 227206, 227207:
r227204:
Fix the typo made in r157474.
r227206:
Before dereferencing intotw() check for NULL, the same way as it is
done for in_pcb (see r157474).
r227207:
Cache SO_REUSEPORT socket option in inpcb-layer in order to avoid
inp_socket->so_options dereference when we may not acquire the lock on
the inpcb.
This fixes the crash due to NULL pointer dereference in
in_pcbbind_setup() when inp_socket->so_options in a pcb returned by
in_pcblookup_local() was checked.
Reported by: dave jones <s.dave.jones at gmail.com>, Arnaud Lacombe <lacombar at gmail.com>
Suggested by: rwatson
Glanced by: rwatson
Tested by: dave jones <s.dave.jones at gmail.com>
Approved by: re (kib)
Modified:
stable/9/sys/netinet/in_pcb.c
stable/9/sys/netinet/in_pcb.h
stable/9/sys/netinet/ip_output.c
stable/9/sys/netinet6/in6_pcb.c
stable/9/sys/netinet6/ip6_output.c
Directory Properties:
stable/9/sys/ (props changed)
stable/9/sys/amd64/include/xen/ (props changed)
stable/9/sys/boot/ (props changed)
stable/9/sys/boot/i386/efi/ (props changed)
stable/9/sys/boot/ia64/efi/ (props changed)
stable/9/sys/boot/ia64/ski/ (props changed)
stable/9/sys/boot/powerpc/boot1.chrp/ (props changed)
stable/9/sys/boot/powerpc/ofw/ (props changed)
stable/9/sys/cddl/contrib/opensolaris/ (props changed)
stable/9/sys/conf/ (props changed)
stable/9/sys/contrib/dev/acpica/ (props changed)
stable/9/sys/contrib/octeon-sdk/ (props changed)
stable/9/sys/contrib/pf/ (props changed)
stable/9/sys/contrib/x86emu/ (props changed)
Modified: stable/9/sys/netinet/in_pcb.c
==============================================================================
--- stable/9/sys/netinet/in_pcb.c Thu Nov 10 20:15:35 2011 (r227427)
+++ stable/9/sys/netinet/in_pcb.c Thu Nov 10 20:28:30 2011 (r227428)
@@ -575,8 +575,7 @@ in_pcbbind_setup(struct inpcb *inp, stru
ntohl(t->inp_faddr.s_addr) == INADDR_ANY) &&
(ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
- (t->inp_socket->so_options &
- SO_REUSEPORT) == 0) &&
+ (t->inp_flags2 & INP_REUSEPORT) == 0) &&
(inp->inp_cred->cr_uid !=
t->inp_cred->cr_uid))
return (EADDRINUSE);
@@ -590,19 +589,19 @@ in_pcbbind_setup(struct inpcb *inp, stru
* being in use (for now). This is better
* than a panic, but not desirable.
*/
- tw = intotw(inp);
+ tw = intotw(t);
if (tw == NULL ||
(reuseport & tw->tw_so_options) == 0)
return (EADDRINUSE);
- } else if (t &&
- (reuseport & t->inp_socket->so_options) == 0) {
+ } else if (t && (reuseport == 0 ||
+ (t->inp_flags2 & INP_REUSEPORT) == 0)) {
#ifdef INET6
if (ntohl(sin->sin_addr.s_addr) !=
INADDR_ANY ||
ntohl(t->inp_laddr.s_addr) !=
INADDR_ANY ||
- INP_SOCKAF(so) ==
- INP_SOCKAF(t->inp_socket))
+ (inp->inp_vflag & INP_IPV6PROTO) == 0 ||
+ (t->inp_vflag & INP_IPV6PROTO) == 0)
#endif
return (EADDRINUSE);
}
Modified: stable/9/sys/netinet/in_pcb.h
==============================================================================
--- stable/9/sys/netinet/in_pcb.h Thu Nov 10 20:15:35 2011 (r227427)
+++ stable/9/sys/netinet/in_pcb.h Thu Nov 10 20:28:30 2011 (r227428)
@@ -540,6 +540,7 @@ void inp_4tuple_get(struct inpcb *inp,
#define INP_LLE_VALID 0x00000001 /* cached lle is valid */
#define INP_RT_VALID 0x00000002 /* cached rtentry is valid */
#define INP_PCBGROUPWILD 0x00000004 /* in pcbgroup wildcard list */
+#define INP_REUSEPORT 0x00000008 /* SO_REUSEPORT option is set */
/*
* Flags passed to in_pcblookup*() functions.
Modified: stable/9/sys/netinet/ip_output.c
==============================================================================
--- stable/9/sys/netinet/ip_output.c Thu Nov 10 20:15:35 2011 (r227427)
+++ stable/9/sys/netinet/ip_output.c Thu Nov 10 20:28:30 2011 (r227428)
@@ -895,12 +895,43 @@ ip_ctloutput(struct socket *so, struct s
error = optval = 0;
if (sopt->sopt_level != IPPROTO_IP) {
- if ((sopt->sopt_level == SOL_SOCKET) &&
- (sopt->sopt_name == SO_SETFIB)) {
- inp->inp_inc.inc_fibnum = so->so_fibnum;
- return (0);
+ error = EINVAL;
+
+ if (sopt->sopt_level == SOL_SOCKET &&
+ sopt->sopt_dir == SOPT_SET) {
+ switch (sopt->sopt_name) {
+ case SO_REUSEADDR:
+ INP_WLOCK(inp);
+ if (IN_MULTICAST(ntohl(inp->inp_laddr.s_addr))) {
+ if ((so->so_options &
+ (SO_REUSEADDR | SO_REUSEPORT)) != 0)
+ inp->inp_flags2 |= INP_REUSEPORT;
+ else
+ inp->inp_flags2 &= ~INP_REUSEPORT;
+ }
+ INP_WUNLOCK(inp);
+ error = 0;
+ break;
+ case SO_REUSEPORT:
+ INP_WLOCK(inp);
+ if ((so->so_options & SO_REUSEPORT) != 0)
+ inp->inp_flags2 |= INP_REUSEPORT;
+ else
+ inp->inp_flags2 &= ~INP_REUSEPORT;
+ INP_WUNLOCK(inp);
+ error = 0;
+ break;
+ case SO_SETFIB:
+ INP_WLOCK(inp);
+ inp->inp_inc.inc_fibnum = so->so_fibnum;
+ INP_WUNLOCK(inp);
+ error = 0;
+ break;
+ default:
+ break;
+ }
}
- return (EINVAL);
+ return (error);
}
switch (sopt->sopt_dir) {
Modified: stable/9/sys/netinet6/in6_pcb.c
==============================================================================
--- stable/9/sys/netinet6/in6_pcb.c Thu Nov 10 20:15:35 2011 (r227427)
+++ stable/9/sys/netinet6/in6_pcb.c Thu Nov 10 20:28:30 2011 (r227428)
@@ -187,6 +187,7 @@ in6_pcbbind(register struct inpcb *inp,
}
if (lport) {
struct inpcb *t;
+ struct tcptw *tw;
/* GROSS */
if (ntohs(lport) <= V_ipport_reservedhigh &&
@@ -206,8 +207,8 @@ in6_pcbbind(register struct inpcb *inp,
IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) &&
(!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
!IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
- (t->inp_socket->so_options & SO_REUSEPORT)
- == 0) && (inp->inp_cred->cr_uid !=
+ (t->inp_flags2 & INP_REUSEPORT) == 0) &&
+ (inp->inp_cred->cr_uid !=
t->inp_cred->cr_uid))
return (EADDRINUSE);
#ifdef INET
@@ -233,10 +234,21 @@ in6_pcbbind(register struct inpcb *inp,
}
t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
lport, lookupflags, cred);
- if (t && (reuseport & ((t->inp_flags & INP_TIMEWAIT) ?
- intotw(t)->tw_so_options :
- t->inp_socket->so_options)) == 0)
+ if (t && (t->inp_flags & INP_TIMEWAIT)) {
+ /*
+ * XXXRW: If an incpb has had its timewait
+ * state recycled, we treat the address as
+ * being in use (for now). This is better
+ * than a panic, but not desirable.
+ */
+ tw = intotw(t);
+ if (tw == NULL ||
+ (reuseport & tw->tw_so_options) == 0)
+ return (EADDRINUSE);
+ } else if (t && (reuseport & t->inp_socket->so_options)
+ == 0) {
return (EADDRINUSE);
+ }
#ifdef INET
if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
@@ -246,19 +258,19 @@ in6_pcbbind(register struct inpcb *inp,
t = in_pcblookup_local(pcbinfo, sin.sin_addr,
lport, lookupflags, cred);
if (t && t->inp_flags & INP_TIMEWAIT) {
- if ((reuseport &
- intotw(t)->tw_so_options) == 0 &&
- (ntohl(t->inp_laddr.s_addr) !=
+ tw = intotw(t);
+ if (tw == NULL)
+ return (EADDRINUSE);
+ if ((reuseport & tw->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)))
+ } else if (t && (reuseport == 0 ||
+ (t->inp_flags2 & INP_REUSEPORT) == 0) &&
+ (ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
+ (t->inp_vflag & INP_IPV6PROTO) == 0))
return (EADDRINUSE);
}
#endif
Modified: stable/9/sys/netinet6/ip6_output.c
==============================================================================
--- stable/9/sys/netinet6/ip6_output.c Thu Nov 10 20:15:35 2011 (r227427)
+++ stable/9/sys/netinet6/ip6_output.c Thu Nov 10 20:28:30 2011 (r227428)
@@ -1421,7 +1421,38 @@ ip6_ctloutput(struct socket *so, struct
optval = 0;
uproto = (int)so->so_proto->pr_protocol;
- if (level == IPPROTO_IPV6) {
+ if (level != IPPROTO_IPV6) {
+ error = EINVAL;
+
+ if (sopt->sopt_level == SOL_SOCKET &&
+ sopt->sopt_dir == SOPT_SET) {
+ switch (sopt->sopt_name) {
+ case SO_REUSEADDR:
+ INP_WLOCK(in6p);
+ if (IN_MULTICAST(ntohl(in6p->inp_laddr.s_addr))) {
+ if ((so->so_options &
+ (SO_REUSEADDR | SO_REUSEPORT)) != 0)
+ in6p->inp_flags2 |= INP_REUSEPORT;
+ else
+ in6p->inp_flags2 &= ~INP_REUSEPORT;
+ }
+ INP_WUNLOCK(in6p);
+ error = 0;
+ break;
+ case SO_REUSEPORT:
+ INP_WLOCK(in6p);
+ if ((so->so_options & SO_REUSEPORT) != 0)
+ in6p->inp_flags2 |= INP_REUSEPORT;
+ else
+ in6p->inp_flags2 &= ~INP_REUSEPORT;
+ INP_WUNLOCK(in6p);
+ error = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ } else { /* level == IPPROTO_IPV6 */
switch (op) {
case SOPT_SET:
@@ -2044,8 +2075,6 @@ do { \
}
break;
}
- } else { /* level != IPPROTO_IPV6 */
- error = EINVAL;
}
return (error);
}
More information about the svn-src-stable-9
mailing list