Commit 0b8d9073 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso

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: 48596a8d ("netfilter: ipset: Fix adding an IPv4 range containing more than 2^31 addresses")
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent da17c73b
...@@ -168,7 +168,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -168,7 +168,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 }; struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, p = 0, port, port_to; 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; bool with_ports = false;
u8 cidr; u8 cidr;
int ret; int ret;
...@@ -269,22 +269,21 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -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); ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
} }
if (retried) if (retried) {
ip = ntohl(h->next.ip); 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++) { for (; ip <= ip_to; ip++) {
e.ip = htonl(ip); e.ip = htonl(ip);
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
e.port = htons(p); e.port = htons(p);
ip2 = retried && do {
ip == ntohl(h->next.ip) &&
p == ntohs(h->next.port)
? ntohl(h->next.ip2) : ip2_from;
while (ip2 <= ip2_to) {
e.ip2 = htonl(ip2); e.ip2 = htonl(ip2);
ip2_last = ip_set_range_to_cidr(ip2, ip2_to, ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr);
&cidr);
e.cidr = cidr - 1; e.cidr = cidr - 1;
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
...@@ -292,9 +291,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -292,9 +291,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret; return ret;
ret = 0; ret = 0;
ip2 = ip2_last + 1; } while (ip2++ < ip2_to);
} ip2 = ip2_from;
} }
p = port;
} }
return ret; return ret;
} }
......
...@@ -143,7 +143,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -143,7 +143,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem e = { .cidr = HOST_MASK }; struct hash_net4_elem e = { .cidr = HOST_MASK };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 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; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -193,16 +193,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -193,16 +193,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
while (ip <= ip_to) { do {
e.ip = htonl(ip); 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); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
ret = 0; ret = 0;
ip = last + 1; } while (ip++ < ip_to);
}
return ret; return ret;
} }
......
...@@ -200,7 +200,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -200,7 +200,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 }; struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 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; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -255,17 +255,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -255,17 +255,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
while (ip <= ip_to) { do {
e.ip = htonl(ip); 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); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
ret = 0; ret = 0;
ip = last + 1; } while (ip++ < ip_to);
}
return ret; return ret;
} }
......
...@@ -169,8 +169,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -169,8 +169,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netnet4_elem e = { }; struct hash_netnet4_elem e = { };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, last; u32 ip = 0, ip_to = 0;
u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2; u32 ip2 = 0, ip2_from = 0, ip2_to = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -247,27 +247,27 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -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]); ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
} }
if (retried) if (retried) {
ip = ntohl(h->next.ip[0]); 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); e.ip[0] = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]); ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
ip2 = (retried && do {
ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
: ip2_from;
while (ip2 <= ip2_to) {
e.ip[1] = htonl(ip2); 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); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
ret = 0; ret = 0;
ip2 = last2 + 1; } while (ip2++ < ip2_to);
} ip2 = ip2_from;
ip = last + 1; } while (ip++ < ip_to);
}
return ret; return ret;
} }
......
...@@ -161,7 +161,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -161,7 +161,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 }; struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 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; bool with_ports = false;
u8 cidr; u8 cidr;
int ret; int ret;
...@@ -239,25 +239,26 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -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); ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
} }
if (retried) if (retried) {
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
while (ip <= ip_to) { p = ntohs(h->next.port);
} else {
p = port;
}
do {
e.ip = htonl(ip); 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; e.cidr = cidr - 1;
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
e.port = htons(p); e.port = htons(p);
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
ret = 0; ret = 0;
} }
ip = last + 1; p = port;
} } while (ip++ < ip_to);
return ret; return ret;
} }
......
...@@ -184,8 +184,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -184,8 +184,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netportnet4_elem e = { }; struct hash_netportnet4_elem e = { };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set); struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to; 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; bool with_ports = false;
int ret; int ret;
...@@ -288,33 +288,34 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -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]); ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
} }
if (retried) if (retried) {
ip = ntohl(h->next.ip[0]); 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); e.ip[0] = htonl(ip);
ip_last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]); ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
e.port = htons(p); e.port = htons(p);
ip2 = (retried && ip == ntohl(h->next.ip[0]) && do {
p == ntohs(h->next.port)) ? ntohl(h->next.ip[1])
: ip2_from;
while (ip2 <= ip2_to) {
e.ip[1] = htonl(ip2); e.ip[1] = htonl(ip2);
ip2_last = ip_set_range_to_cidr(ip2, ip2_to, ip2 = ip_set_range_to_cidr(ip2, ip2_to,
&e.cidr[1]); &e.cidr[1]);
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
ret = 0; 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; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment