Author: jtl
Date: Tue Aug 14 17:24:26 2018
New Revision: 337781
URL: https://svnweb.freebsd.org/changeset/base/337781

Log:
  Make the IPv6 fragment limits be global, rather than per-VNET, limits.
  
  The IPv6 reassembly fragment limit is based on the number of mbuf clusters,
  which are a global resource. However, the limit is currently applied
  on a per-VNET basis. Given enough VNETs (or given sufficient customization
  on enough VNETs), it is possible that the sum of all the VNET fragment
  limits will exceed the number of mbuf clusters available in the system.
  
  Given the fact that the fragment limits are intended (at least in part) to
  regulate access to a global resource, the IPv6 fragment limit should
  be applied on a global basis.
  
  Note that it is still possible to disable fragmentation for a particular
  VNET by setting the net.inet6.ip6.maxfragpackets sysctl to 0 for that
  VNET. In addition, it is now possible to disable fragmentation globally
  by setting the net.inet6.ip6.maxfrags sysctl to 0.
  
  Reviewed by:  jhb
  Security:     FreeBSD-SA-18:10.ip
  Security:     CVE-2018-6923

Modified:
  head/sys/netinet6/frag6.c
  head/sys/netinet6/in6_proto.c
  head/sys/netinet6/ip6_var.h

Modified: head/sys/netinet6/frag6.c
==============================================================================
--- head/sys/netinet6/frag6.c   Tue Aug 14 17:23:05 2018        (r337780)
+++ head/sys/netinet6/frag6.c   Tue Aug 14 17:24:26 2018        (r337781)
@@ -89,12 +89,11 @@ struct ip6qbucket {
 };
 
 VNET_DEFINE_STATIC(volatile u_int, frag6_nfragpackets);
-VNET_DEFINE_STATIC(volatile u_int, frag6_nfrags);
+volatile u_int frag6_nfrags = 0;
 VNET_DEFINE_STATIC(struct ip6qbucket, ip6q[IP6REASS_NHASH]);
 VNET_DEFINE_STATIC(uint32_t, ip6q_hashseed);
 
 #define        V_frag6_nfragpackets            VNET(frag6_nfragpackets)
-#define        V_frag6_nfrags                  VNET(frag6_nfrags)
 #define        V_ip6q                          VNET(ip6q)
 #define        V_ip6q_hashseed                 VNET(ip6q_hashseed)
 
@@ -112,9 +111,16 @@ static MALLOC_DEFINE(M_FTABLE, "fragment", "fragment r
 static void
 frag6_change(void *tag)
 {
+       VNET_ITERATOR_DECL(vnet_iter);
 
-       V_ip6_maxfragpackets = nmbclusters / 4;
-       V_ip6_maxfrags = nmbclusters / 4;
+       ip6_maxfrags = nmbclusters / 4;
+       VNET_LIST_RLOCK_NOSLEEP();
+       VNET_FOREACH(vnet_iter) {
+               CURVNET_SET(vnet_iter);
+               V_ip6_maxfragpackets = nmbclusters / 4;
+               CURVNET_RESTORE();
+       }
+       VNET_LIST_RUNLOCK_NOSLEEP();
 }
 
 void
@@ -124,7 +130,6 @@ frag6_init(void)
        int i;
 
        V_ip6_maxfragpackets = nmbclusters / 4;
-       V_ip6_maxfrags = nmbclusters / 4;
        for (i = 0; i < IP6REASS_NHASH; i++) {
                q6 = IP6Q_HEAD(i);
                q6->ip6q_next = q6->ip6q_prev = q6;
@@ -134,6 +139,7 @@ frag6_init(void)
        if (!IS_DEFAULT_VNET(curvnet))
                return;
 
+       ip6_maxfrags = nmbclusters / 4;
        EVENTHANDLER_REGISTER(nmbclusters_change,
            frag6_change, NULL, EVENTHANDLER_PRI_ANY);
 }
@@ -267,9 +273,9 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
         * If maxfrag is 0, never accept fragments.
         * If maxfrag is -1, accept all fragments without limitation.
         */
-       if (V_ip6_maxfrags < 0)
+       if (ip6_maxfrags < 0)
                ;
-       else if (atomic_load_int(&V_frag6_nfrags) >= (u_int)V_ip6_maxfrags)
+       else if (atomic_load_int(&frag6_nfrags) >= (u_int)ip6_maxfrags)
                goto dropfrag;
 
        for (q6 = head->ip6q_next; q6 != head; q6 = q6->ip6q_next)
@@ -531,7 +537,7 @@ insert:
         * the most recently active fragmented packet.
         */
        frag6_enq(ip6af, af6->ip6af_up, hash);
-       atomic_add_int(&V_frag6_nfrags, 1);
+       atomic_add_int(&frag6_nfrags, 1);
        q6->ip6q_nfrag++;
 #if 0 /* xxx */
        if (q6 != head->ip6q_next) {
@@ -595,7 +601,7 @@ insert:
 
        if (ip6_deletefraghdr(m, offset, M_NOWAIT) != 0) {
                frag6_remque(q6, hash);
-               atomic_subtract_int(&V_frag6_nfrags, q6->ip6q_nfrag);
+               atomic_subtract_int(&frag6_nfrags, q6->ip6q_nfrag);
 #ifdef MAC
                mac_ip6q_destroy(q6);
 #endif
@@ -612,7 +618,7 @@ insert:
            (caddr_t)&nxt);
 
        frag6_remque(q6, hash);
-       atomic_subtract_int(&V_frag6_nfrags, q6->ip6q_nfrag);
+       atomic_subtract_int(&frag6_nfrags, q6->ip6q_nfrag);
 #ifdef MAC
        mac_ip6q_reassemble(q6, m);
        mac_ip6q_destroy(q6);
@@ -708,7 +714,7 @@ frag6_freef(struct ip6q *q6, uint32_t bucket)
                free(af6, M_FTABLE);
        }
        frag6_remque(q6, bucket);
-       atomic_subtract_int(&V_frag6_nfrags, q6->ip6q_nfrag);
+       atomic_subtract_int(&frag6_nfrags, q6->ip6q_nfrag);
 #ifdef MAC
        mac_ip6q_destroy(q6);
 #endif

Modified: head/sys/netinet6/in6_proto.c
==============================================================================
--- head/sys/netinet6/in6_proto.c       Tue Aug 14 17:23:05 2018        
(r337780)
+++ head/sys/netinet6/in6_proto.c       Tue Aug 14 17:24:26 2018        
(r337781)
@@ -385,7 +385,7 @@ VNET_DEFINE(int, ip6_no_radr) = 0;
 VNET_DEFINE(int, ip6_norbit_raif) = 0;
 VNET_DEFINE(int, ip6_rfc6204w3) = 0;
 VNET_DEFINE(int, ip6_maxfragpackets);  /* initialized in frag6.c:frag6_init() 
*/
-VNET_DEFINE(int, ip6_maxfrags);                /* initialized in 
frag6.c:frag6_init() */
+int ip6_maxfrags;              /* initialized in frag6.c:frag6_init() */
 VNET_DEFINE(int, ip6_log_interval) = 5;
 VNET_DEFINE(int, ip6_hdrnestlimit) = 15;/* How many header options will we
                                         * process? */
@@ -559,8 +559,10 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USE_DEFAULTZONE, us
        CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_use_defzone), 0,
        "Use the default scope zone when none is specified");
 SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGS, maxfrags,
-       CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_maxfrags), 0,
-       "Maximum allowed number of outstanding IPv6 packet fragments");
+       CTLFLAG_RW, &ip6_maxfrags, 0,
+       "Maximum allowed number of outstanding IPv6 packet fragments. "
+       "A value of 0 means no fragmented packets will be accepted, while a "
+       "a value of -1 means no limit");
 SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MCAST_PMTU, mcast_pmtu,
        CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_mcast_pmtu), 0,
        "Enable path MTU discovery for multicast packets");

Modified: head/sys/netinet6/ip6_var.h
==============================================================================
--- head/sys/netinet6/ip6_var.h Tue Aug 14 17:23:05 2018        (r337780)
+++ head/sys/netinet6/ip6_var.h Tue Aug 14 17:24:26 2018        (r337781)
@@ -301,7 +301,7 @@ VNET_DECLARE(struct socket *, ip6_mrouter); /* multica
 VNET_DECLARE(int, ip6_sendredirects);  /* send IP redirects when forwarding? */
 VNET_DECLARE(int, ip6_maxfragpackets); /* Maximum packets in reassembly
                                         * queue */
-VNET_DECLARE(int, ip6_maxfrags);       /* Maximum fragments in reassembly
+extern int ip6_maxfrags;               /* Maximum fragments in reassembly
                                         * queue */
 VNET_DECLARE(int, ip6_accept_rtadv);   /* Acts as a host not a router */
 VNET_DECLARE(int, ip6_no_radr);                /* No defroute from RA */
@@ -317,7 +317,6 @@ VNET_DECLARE(int, ip6_dad_count);   /* DupAddrDetectionT
 #define        V_ip6_mrouter                   VNET(ip6_mrouter)
 #define        V_ip6_sendredirects             VNET(ip6_sendredirects)
 #define        V_ip6_maxfragpackets            VNET(ip6_maxfragpackets)
-#define        V_ip6_maxfrags                  VNET(ip6_maxfrags)
 #define        V_ip6_accept_rtadv              VNET(ip6_accept_rtadv)
 #define        V_ip6_no_radr                   VNET(ip6_no_radr)
 #define        V_ip6_norbit_raif               VNET(ip6_norbit_raif)
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to