aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesper Skriver <jesper@FreeBSD.org>2001-08-05 23:08:38 +0000
committerJesper Skriver <jesper@FreeBSD.org>2001-08-05 23:08:38 +0000
commit695cd75e174099a006f4fd74c0aee082a63e2a58 (patch)
treea642a36e3ee2c26eb78ba280c6e4a613cb79f4f3
parent12fd6b67053a76f180ab2e1d8c7a9c9b897d0fde (diff)
downloadsrc-695cd75e174099a006f4fd74c0aee082a63e2a58.tar.gz
src-695cd75e174099a006f4fd74c0aee082a63e2a58.zip
MFS
src/sys/netinet/ip_input.c rev 1.130.2.22 src/sys/netinet6/frag6.c rev 1.2.2.4 src/sys/netinet6/in6_proto.c rev 1.6.2.4 Prevent denial of service using bogus fragmented IPv4 packets. A attacker sending a lot of bogus fragmented packets to the target (with different IPv4 identification field - ip_id), may be able to put the target machine into mbuf starvation state. By setting a upper limit on the number of reassembly queues we prevent this situation. This upper limit is controlled by the new sysctl net.inet.ip.maxfragpackets which defaults to nmbclusters/4 If you want old behaviour (no upper limit) set this sysctl to a negative value. If you don't want to accept any fragments (not recommended) set the sysctl to 0 (zero) Change the default value of net.inet6.ip6.maxfragpackets from 200 to nmbclusters/4 to match the IPv4 case. Approved by: security-officer (kris) Obtained from: NetBSD (partially)
Notes
Notes: svn path=/releng/4.3/; revision=81171
-rw-r--r--sys/netinet/ip_input.c34
-rw-r--r--sys/netinet6/frag6.c2
-rw-r--r--sys/netinet6/in6_proto.c2
3 files changed, 36 insertions, 2 deletions
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 1dd47a236115..24a97719b443 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -122,6 +122,12 @@ SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
&ip_keepfaith, 0,
"Enable packet capture for FAITH IPv4->IPv6 translater daemon");
+static int ip_nfragpackets = 0;
+static int ip_maxfragpackets; /* initialized in ip_init() */
+SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW,
+ &ip_maxfragpackets, 0,
+ "Maximum number of IPv4 fragment reassembly queue entries");
+
/*
* XXX - Setting ip_checkinterface mostly implements the receive side of
* the Strong ES model described in RFC 1122, but since the routing table
@@ -248,7 +254,8 @@ ip_init()
for (i = 0; i < IPREASS_NHASH; i++)
ipq[i].next = ipq[i].prev = &ipq[i];
- maxnipq = nmbclusters/4;
+ maxnipq = nmbclusters / 4;
+ ip_maxfragpackets = nmbclusters / 4;
ip_id = time_second & 0xffff;
ipintrq.ifq_maxlen = ipqmaxlen;
@@ -861,6 +868,15 @@ ip_reass(m, fp, where)
* If first fragment to arrive, create a reassembly queue.
*/
if (fp == 0) {
+ /*
+ * Enforce upper bound on number of fragmented packets
+ * for which we attempt reassembly;
+ * If maxfrag is 0, never accept fragments.
+ * If maxfrag is -1, accept all fragments without limitation.
+ */
+ if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets))
+ goto dropfrag;
+ ip_nfragpackets++;
if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
goto dropfrag;
fp = mtod(t, struct ipq *);
@@ -1009,6 +1025,7 @@ inserted:
remque(fp);
nipq--;
(void) m_free(dtom(fp));
+ ip_nfragpackets--;
m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2);
m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2);
/* some debugging cruft by sklower, below, will go away soon */
@@ -1049,6 +1066,7 @@ ip_freef(fp)
}
remque(fp);
(void) m_free(dtom(fp));
+ ip_nfragpackets--;
nipq--;
}
@@ -1077,6 +1095,20 @@ ip_slowtimo()
}
}
}
+ /*
+ * If we are over the maximum number of fragments
+ * (due to the limit being lowered), drain off
+ * enough to get down to the new limit.
+ */
+ for (i = 0; i < IPREASS_NHASH; i++) {
+ if (ip_maxfragpackets >= 0) {
+ while ((ip_nfragpackets > ip_maxfragpackets) &&
+ (ipq[i].next != &ipq[i])) {
+ ipstat.ips_fragdropped++;
+ ip_freef(ipq[i].next);
+ }
+ }
+ }
ipflow_slowtimo();
splx(s);
}
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
index d78335719428..d586ad8c2baf 100644
--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -81,6 +81,8 @@ frag6_init()
{
struct timeval tv;
+ ip6_maxfragpackets = nmbclusters / 4;
+
/*
* in many cases, random() here does NOT return random number
* as initialization during bootstrap time occur in fixed order.
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index f7b1a6b97ba5..4cd57a6634e5 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -286,7 +286,7 @@ int ip6_sendredirects = IPV6_SENDREDIRECTS;
int ip6_defhlim = IPV6_DEFHLIM;
int ip6_defmcasthlim = IPV6_DEFAULT_MULTICAST_HOPS;
int ip6_accept_rtadv = 0; /* "IPV6FORWARDING ? 0 : 1" is dangerous */
-int ip6_maxfragpackets = 200;
+int ip6_maxfragpackets; /* initialized in frag6.c:frag6_init() */
int ip6_log_interval = 5;
int ip6_hdrnestlimit = 50; /* appropriate? */
int ip6_dad_count = 1; /* DupAddrDetectionTransmits */