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
This commit is contained in:
parent
ff790bbad0
commit
2adfd64f35
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=337781
@ -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 reassembly header");
|
||||
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 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
|
||||
* 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 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
|
||||
|
||||
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 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
|
||||
(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
|
||||
|
@ -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, use_defaultzone,
|
||||
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");
|
||||
|
@ -301,7 +301,7 @@ VNET_DECLARE(struct socket *, ip6_mrouter); /* multicast routing daemon */
|
||||
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); /* DupAddrDetectionTransmits */
|
||||
#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)
|
||||
|
Loading…
Reference in New Issue
Block a user