From c774433e2ab74782456abf9444fd4478e09ca746 Mon Sep 17 00:00:00 2001 From: David Limbeck Date: Wed, 20 Feb 2019 14:08:22 +0100 Subject: [PATCH] add patch to fix ipset memory exhaustion Add a patch from upstream until it is fixed in the Ubuntu 4.15 kernel. Signed-off-by: David Limbeck --- ...pset-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 +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 +Signed-off-by: Pablo Neira Ayuso +--- + 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.39.2