[pve-devel] [PATCH kernel] add patch to fix ipset memory exhaustion

David Limbeck d.limbeck at proxmox.com
Wed Feb 20 14:08:22 CET 2019


Add a patch from upstream until it is fixed in the Ubuntu 4.15 kernel.

Signed-off-by: David Limbeck <d.limbeck at proxmox.com>
---
 ...ter-ipset-Fix-wraparound-n-hash-net-types.patch | 318 +++++++++++++++++++++
 1 file changed, 318 insertions(+)
 create mode 100644 patches/kernel/0010-netfilter-ipset-Fix-wraparound-n-hash-net-types.patch

diff --git a/patches/kernel/0010-netfilter-ipset-Fix-wraparound-n-hash-net-types.patch b/patches/kernel/0010-netfilter-ipset-Fix-wraparound-n-hash-net-types.patch
new file mode 100644
index 0000000..282e380
--- /dev/null
+++ b/patches/kernel/0010-netfilter-ipset-Fix-wraparound-n-hash-net-types.patch
@@ -0,0 +1,318 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jozsef Kadlecsik <kadlec at blackhole.kfki.hu>
+Date: Fri, 12 Jan 2018 11:16:50 +0100
+Subject: [PATCH] netfilter: ipset: Fix wraparound in hash:*net* types
+
+Fix wraparound bug which could lead to memory exhaustion when adding an
+x.x.x.x-255.255.255.255 range to any hash:*net* types.
+
+Fixes Netfilter's bugzilla id #1212, reported by Thomas Schwark.
+
+Fixes: 48596a8ddc46 ("netfilter: ipset: Fix adding an IPv4 range containing more than 2^31 addresses")
+Signed-off-by: Jozsef Kadlecsik <kadlec at blackhole.kfki.hu>
+Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>
+---
+ net/netfilter/ipset/ip_set_hash_ipportnet.c  | 26 ++++++++++-----------
+ net/netfilter/ipset/ip_set_hash_net.c        |  9 ++++---
+ net/netfilter/ipset/ip_set_hash_netiface.c   |  9 ++++---
+ net/netfilter/ipset/ip_set_hash_netnet.c     | 28 +++++++++++-----------
+ net/netfilter/ipset/ip_set_hash_netport.c    | 19 ++++++++-------
+ net/netfilter/ipset/ip_set_hash_netportnet.c | 35 ++++++++++++++--------------
+ 6 files changed, 63 insertions(+), 63 deletions(-)
+
+diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
+index 0f164e986bf1..88b83d6d3084 100644
+--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
++++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
+@@ -168,7 +168,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 	struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
+ 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ 	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
+-	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
++	u32 ip2_from = 0, ip2_to = 0, ip2;
+ 	bool with_ports = false;
+ 	u8 cidr;
+ 	int ret;
+@@ -269,22 +269,21 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
+ 	}
+ 
+-	if (retried)
++	if (retried) {
+ 		ip = ntohl(h->next.ip);
++		p = ntohs(h->next.port);
++		ip2 = ntohl(h->next.ip2);
++	} else {
++		p = port;
++		ip2 = ip2_from;
++	}
+ 	for (; ip <= ip_to; ip++) {
+ 		e.ip = htonl(ip);
+-		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
+-						       : port;
+ 		for (; p <= port_to; p++) {
+ 			e.port = htons(p);
+-			ip2 = retried &&
+-			      ip == ntohl(h->next.ip) &&
+-			      p == ntohs(h->next.port)
+-				? ntohl(h->next.ip2) : ip2_from;
+-			while (ip2 <= ip2_to) {
++			do {
+ 				e.ip2 = htonl(ip2);
+-				ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
+-								&cidr);
++				ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr);
+ 				e.cidr = cidr - 1;
+ 				ret = adtfn(set, &e, &ext, &ext, flags);
+ 
+@@ -292,9 +291,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 					return ret;
+ 
+ 				ret = 0;
+-				ip2 = ip2_last + 1;
+-			}
++			} while (ip2++ < ip2_to);
++			ip2 = ip2_from;
+ 		}
++		p = port;
+ 	}
+ 	return ret;
+ }
+diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
+index 1c67a1761e45..5449e23af13a 100644
+--- a/net/netfilter/ipset/ip_set_hash_net.c
++++ b/net/netfilter/ipset/ip_set_hash_net.c
+@@ -143,7 +143,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 	ipset_adtfn adtfn = set->variant->adt[adt];
+ 	struct hash_net4_elem e = { .cidr = HOST_MASK };
+ 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+-	u32 ip = 0, ip_to = 0, last;
++	u32 ip = 0, ip_to = 0;
+ 	int ret;
+ 
+ 	if (tb[IPSET_ATTR_LINENO])
+@@ -193,16 +193,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 	}
+ 	if (retried)
+ 		ip = ntohl(h->next.ip);
+-	while (ip <= ip_to) {
++	do {
+ 		e.ip = htonl(ip);
+-		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
++		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
+ 		ret = adtfn(set, &e, &ext, &ext, flags);
+ 		if (ret && !ip_set_eexist(ret, flags))
+ 			return ret;
+ 
+ 		ret = 0;
+-		ip = last + 1;
+-	}
++	} while (ip++ < ip_to);
+ 	return ret;
+ }
+ 
+diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
+index d417074f1c1a..f5164c1efce2 100644
+--- a/net/netfilter/ipset/ip_set_hash_netiface.c
++++ b/net/netfilter/ipset/ip_set_hash_netiface.c
+@@ -200,7 +200,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 	ipset_adtfn adtfn = set->variant->adt[adt];
+ 	struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
+ 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+-	u32 ip = 0, ip_to = 0, last;
++	u32 ip = 0, ip_to = 0;
+ 	int ret;
+ 
+ 	if (tb[IPSET_ATTR_LINENO])
+@@ -255,17 +255,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 
+ 	if (retried)
+ 		ip = ntohl(h->next.ip);
+-	while (ip <= ip_to) {
++	do {
+ 		e.ip = htonl(ip);
+-		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
++		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
+ 		ret = adtfn(set, &e, &ext, &ext, flags);
+ 
+ 		if (ret && !ip_set_eexist(ret, flags))
+ 			return ret;
+ 
+ 		ret = 0;
+-		ip = last + 1;
+-	}
++	} while (ip++ < ip_to);
+ 	return ret;
+ }
+ 
+diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c
+index 7f9ae2e9645b..5a2b923bd81f 100644
+--- a/net/netfilter/ipset/ip_set_hash_netnet.c
++++ b/net/netfilter/ipset/ip_set_hash_netnet.c
+@@ -169,8 +169,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 	ipset_adtfn adtfn = set->variant->adt[adt];
+ 	struct hash_netnet4_elem e = { };
+ 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+-	u32 ip = 0, ip_to = 0, last;
+-	u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2;
++	u32 ip = 0, ip_to = 0;
++	u32 ip2 = 0, ip2_from = 0, ip2_to = 0;
+ 	int ret;
+ 
+ 	if (tb[IPSET_ATTR_LINENO])
+@@ -247,27 +247,27 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
+ 	}
+ 
+-	if (retried)
++	if (retried) {
+ 		ip = ntohl(h->next.ip[0]);
++		ip2 = ntohl(h->next.ip[1]);
++	} else {
++		ip2 = ip2_from;
++	}
+ 
+-	while (ip <= ip_to) {
++	do {
+ 		e.ip[0] = htonl(ip);
+-		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
+-		ip2 = (retried &&
+-		       ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
+-						   : ip2_from;
+-		while (ip2 <= ip2_to) {
++		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
++		do {
+ 			e.ip[1] = htonl(ip2);
+-			last2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
++			ip2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
+ 			ret = adtfn(set, &e, &ext, &ext, flags);
+ 			if (ret && !ip_set_eexist(ret, flags))
+ 				return ret;
+ 
+ 			ret = 0;
+-			ip2 = last2 + 1;
+-		}
+-		ip = last + 1;
+-	}
++		} while (ip2++ < ip2_to);
++		ip2 = ip2_from;
++	} while (ip++ < ip_to);
+ 	return ret;
+ }
+ 
+diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
+index e6ef382febe4..1a187be9ebc8 100644
+--- a/net/netfilter/ipset/ip_set_hash_netport.c
++++ b/net/netfilter/ipset/ip_set_hash_netport.c
+@@ -161,7 +161,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 	ipset_adtfn adtfn = set->variant->adt[adt];
+ 	struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
+ 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+-	u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
++	u32 port, port_to, p = 0, ip = 0, ip_to = 0;
+ 	bool with_ports = false;
+ 	u8 cidr;
+ 	int ret;
+@@ -239,25 +239,26 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 		ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
+ 	}
+ 
+-	if (retried)
++	if (retried) {
+ 		ip = ntohl(h->next.ip);
+-	while (ip <= ip_to) {
++		p = ntohs(h->next.port);
++	} else {
++		p = port;
++	}
++	do {
+ 		e.ip = htonl(ip);
+-		last = ip_set_range_to_cidr(ip, ip_to, &cidr);
++		ip = ip_set_range_to_cidr(ip, ip_to, &cidr);
+ 		e.cidr = cidr - 1;
+-		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
+-						       : port;
+ 		for (; p <= port_to; p++) {
+ 			e.port = htons(p);
+ 			ret = adtfn(set, &e, &ext, &ext, flags);
+-
+ 			if (ret && !ip_set_eexist(ret, flags))
+ 				return ret;
+ 
+ 			ret = 0;
+ 		}
+-		ip = last + 1;
+-	}
++		p = port;
++	} while (ip++ < ip_to);
+ 	return ret;
+ }
+ 
+diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c
+index 8602f2595a1a..d391485a6acd 100644
+--- a/net/netfilter/ipset/ip_set_hash_netportnet.c
++++ b/net/netfilter/ipset/ip_set_hash_netportnet.c
+@@ -184,8 +184,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 	ipset_adtfn adtfn = set->variant->adt[adt];
+ 	struct hash_netportnet4_elem e = { };
+ 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+-	u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to;
+-	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
++	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
++	u32 ip2_from = 0, ip2_to = 0, ip2;
+ 	bool with_ports = false;
+ 	int ret;
+ 
+@@ -288,33 +288,34 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
+ 		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
+ 	}
+ 
+-	if (retried)
++	if (retried) {
+ 		ip = ntohl(h->next.ip[0]);
++		p = ntohs(h->next.port);
++		ip2 = ntohl(h->next.ip[1]);
++	} else {
++		p = port;
++		ip2 = ip2_from;
++	}
+ 
+-	while (ip <= ip_to) {
++	do {
+ 		e.ip[0] = htonl(ip);
+-		ip_last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
+-		p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
+-							  : port;
++		ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
+ 		for (; p <= port_to; p++) {
+ 			e.port = htons(p);
+-			ip2 = (retried && ip == ntohl(h->next.ip[0]) &&
+-			       p == ntohs(h->next.port)) ? ntohl(h->next.ip[1])
+-							 : ip2_from;
+-			while (ip2 <= ip2_to) {
++			do {
+ 				e.ip[1] = htonl(ip2);
+-				ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
+-								&e.cidr[1]);
++				ip2 = ip_set_range_to_cidr(ip2, ip2_to,
++							   &e.cidr[1]);
+ 				ret = adtfn(set, &e, &ext, &ext, flags);
+ 				if (ret && !ip_set_eexist(ret, flags))
+ 					return ret;
+ 
+ 				ret = 0;
+-				ip2 = ip2_last + 1;
+-			}
++			} while (ip2++ < ip2_to);
++			ip2 = ip2_from;
+ 		}
+-		ip = ip_last + 1;
+-	}
++		p = port;
++	} while (ip++ < ip_to);
+ 	return ret;
+ }
+ 
+-- 
+2.11.0
+
-- 
2.11.0





More information about the pve-devel mailing list