The following reply was made to PR kern/179901; it has been noted by GNATS.

From: dfil...@freebsd.org (dfilter service)
To: bug-follo...@freebsd.org
Cc:  
Subject: Re: kern/179901: commit references a PR
Date: Thu,  4 Jul 2013 18:38:19 +0000 (UTC)

 Author: trociny
 Date: Thu Jul  4 18:38:00 2013
 New Revision: 252710
 URL: http://svnweb.freebsd.org/changeset/base/252710
 
 Log:
   In r227207, to fix the issue with possible NULL inp_socket pointer
   dereferencing, when checking for SO_REUSEPORT option (and SO_REUSEADDR
   for multicast), INP_REUSEPORT flag was introduced to cache the socket
   option.  It was decided then that one flag would be enough to cache
   both SO_REUSEPORT and SO_REUSEADDR: when processing SO_REUSEADDR
   setsockopt(2), it was checked if it was called for a multicast address
   and INP_REUSEPORT was set accordingly.
   
   Unfortunately that approach does not work when setsockopt(2) is called
   before binding to a multicast address: the multicast check fails and
   INP_REUSEPORT is not set.
   
   Fix this by adding INP_REUSEADDR flag to unconditionally cache
   SO_REUSEADDR.
   
   PR:          179901
   Submitted by:        Michael Gmelin freebsd grem.de (initial version)
   Reviewed by: rwatson
   MFC after:   1 week
 
 Modified:
   head/sys/netinet/in_pcb.c
   head/sys/netinet/in_pcb.h
   head/sys/netinet/ip_output.c
   head/sys/netinet6/in6_pcb.c
   head/sys/netinet6/ip6_output.c
 
 Modified: head/sys/netinet/in_pcb.c
 ==============================================================================
 --- head/sys/netinet/in_pcb.c  Thu Jul  4 18:00:27 2013        (r252709)
 +++ head/sys/netinet/in_pcb.c  Thu Jul  4 18:38:00 2013        (r252710)
 @@ -467,6 +467,23 @@ in_pcb_lport(struct inpcb *inp, struct i
  
        return (0);
  }
 +
 +/*
 + * Return cached socket options.
 + */
 +short
 +inp_so_options(const struct inpcb *inp)
 +{
 +   short so_options;
 +
 +   so_options = 0;
 +
 +   if ((inp->inp_flags2 & INP_REUSEPORT) != 0)
 +         so_options |= SO_REUSEPORT;
 +   if ((inp->inp_flags2 & INP_REUSEADDR) != 0)
 +         so_options |= SO_REUSEADDR;
 +   return (so_options);
 +}
  #endif /* INET || INET6 */
  
  #ifdef INET
 @@ -595,8 +612,7 @@ in_pcbbind_setup(struct inpcb *inp, stru
                                if (tw == NULL ||
                                    (reuseport & tw->tw_so_options) == 0)
                                        return (EADDRINUSE);
 -                      } else if (t && (reuseport == 0 ||
 -                          (t->inp_flags2 & INP_REUSEPORT) == 0)) {
 +                      } else if (t && (reuseport & inp_so_options(t)) == 0) {
  #ifdef INET6
                                if (ntohl(sin->sin_addr.s_addr) !=
                                    INADDR_ANY ||
 
 Modified: head/sys/netinet/in_pcb.h
 ==============================================================================
 --- head/sys/netinet/in_pcb.h  Thu Jul  4 18:00:27 2013        (r252709)
 +++ head/sys/netinet/in_pcb.h  Thu Jul  4 18:38:00 2013        (r252710)
 @@ -442,6 +442,7 @@ struct tcpcb *
        inp_inpcbtotcpcb(struct inpcb *inp);
  void  inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp,
                uint32_t *faddr, uint16_t *fp);
 +short inp_so_options(const struct inpcb *inp);
  
  #endif /* _KERNEL */
  
 @@ -543,6 +544,7 @@ void       inp_4tuple_get(struct inpcb *inp, 
  #define       INP_PCBGROUPWILD        0x00000004 /* in pcbgroup wildcard list 
*/
  #define       INP_REUSEPORT           0x00000008 /* SO_REUSEPORT option is 
set */
  #define       INP_FREED               0x00000010 /* inp itself is not valid */
 +#define       INP_REUSEADDR           0x00000020 /* SO_REUSEADDR option is 
set */
  
  /*
   * Flags passed to in_pcblookup*() functions.
 
 Modified: head/sys/netinet/ip_output.c
 ==============================================================================
 --- head/sys/netinet/ip_output.c       Thu Jul  4 18:00:27 2013        
(r252709)
 +++ head/sys/netinet/ip_output.c       Thu Jul  4 18:38:00 2013        
(r252710)
 @@ -900,13 +900,10 @@ ip_ctloutput(struct socket *so, struct s
                        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;
 -                              }
 +                              if ((so->so_options & SO_REUSEADDR) != 0)
 +                                      inp->inp_flags2 |= INP_REUSEADDR;
 +                              else
 +                                      inp->inp_flags2 &= ~INP_REUSEADDR;
                                INP_WUNLOCK(inp);
                                error = 0;
                                break;
 
 Modified: head/sys/netinet6/in6_pcb.c
 ==============================================================================
 --- head/sys/netinet6/in6_pcb.c        Thu Jul  4 18:00:27 2013        
(r252709)
 +++ head/sys/netinet6/in6_pcb.c        Thu Jul  4 18:38:00 2013        
(r252710)
 @@ -243,8 +243,7 @@ in6_pcbbind(register struct inpcb *inp, 
                                if (tw == NULL ||
                                    (reuseport & tw->tw_so_options) == 0)
                                        return (EADDRINUSE);
 -                      } else if (t && (reuseport == 0 ||
 -                          (t->inp_flags2 & INP_REUSEPORT) == 0)) {
 +                      } else if (t && (reuseport & inp_so_options(t)) == 0) {
                                return (EADDRINUSE);
                        }
  #ifdef INET
 @@ -265,8 +264,8 @@ in6_pcbbind(register struct inpcb *inp, 
                                             INP_IPV6PROTO) ==
                                             (t->inp_vflag & INP_IPV6PROTO))))
                                                return (EADDRINUSE);
 -                              } else if (t && (reuseport == 0 ||
 -                                  (t->inp_flags2 & INP_REUSEPORT) == 0) &&
 +                              } else if (t &&
 +                                  (reuseport & inp_so_options(t)) == 0 &&
                                    (ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
                                    (t->inp_vflag & INP_IPV6PROTO) != 0))
                                        return (EADDRINUSE);
 
 Modified: head/sys/netinet6/ip6_output.c
 ==============================================================================
 --- head/sys/netinet6/ip6_output.c     Thu Jul  4 18:00:27 2013        
(r252709)
 +++ head/sys/netinet6/ip6_output.c     Thu Jul  4 18:38:00 2013        
(r252710)
 @@ -1477,13 +1477,10 @@ ip6_ctloutput(struct socket *so, struct 
                        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;
 -                              }
 +                              if ((so->so_options & SO_REUSEADDR) != 0)
 +                                      in6p->inp_flags2 |= INP_REUSEADDR;
 +                              else
 +                                      in6p->inp_flags2 &= ~INP_REUSEADDR;
                                INP_WUNLOCK(in6p);
                                error = 0;
                                break;
 _______________________________________________
 svn-src-...@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"
 
_______________________________________________
freebsd-net@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"

Reply via email to