Commit 5f7b51bf authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso

netfilter: ipset: Limit the maximal range of consecutive elements to add/delete

The range size of consecutive elements were not limited. Thus one could
define a huge range which may result soft lockup errors due to the long
execution time. Now the range size is limited to 2^20 entries.
Reported-by: default avatarBrad Spengler <spender@grsecurity.net>
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@netfilter.org>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent c7d10223
...@@ -196,6 +196,9 @@ struct ip_set_region { ...@@ -196,6 +196,9 @@ struct ip_set_region {
u32 elements; /* Number of elements vs timeout */ u32 elements; /* Number of elements vs timeout */
}; };
/* Max range where every element is added/deleted in one step */
#define IPSET_MAX_RANGE (1<<20)
/* The max revision number supported by any set type + 1 */ /* The max revision number supported by any set type + 1 */
#define IPSET_REVISION_MAX 9 #define IPSET_REVISION_MAX 9
......
...@@ -132,8 +132,11 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -132,8 +132,11 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
if (ip > ip_to) if (ip > ip_to) {
if (ip_to == 0)
return -IPSET_ERR_HASH_ELEM;
swap(ip, ip_to); swap(ip, ip_to);
}
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
...@@ -144,6 +147,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -144,6 +147,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
/* 64bit division is not allowed on 32bit */
if (((u64)ip_to - ip + 1) >> (32 - h->netmask) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) { if (retried) {
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
e.ip = htonl(ip); e.ip = htonl(ip);
......
...@@ -121,6 +121,8 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -121,6 +121,8 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK])); e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK]));
e.mark &= h->markmask; e.mark &= h->markmask;
if (e.mark == 0 && e.ip == 0)
return -IPSET_ERR_HASH_ELEM;
if (adt == IPSET_TEST || if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) { !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) {
...@@ -133,8 +135,11 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -133,8 +135,11 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
if (ip > ip_to) if (ip > ip_to) {
if (e.mark == 0 && ip_to == 0)
return -IPSET_ERR_HASH_ELEM;
swap(ip, ip_to); swap(ip, ip_to);
}
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
...@@ -143,6 +148,9 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -143,6 +148,9 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
ip_set_mask_from_to(ip, ip_to, cidr); ip_set_mask_from_to(ip, ip_to, cidr);
} }
if (((u64)ip_to - ip + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
for (; ip <= ip_to; ip++) { for (; ip <= ip_to; ip++) {
......
...@@ -173,6 +173,9 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -173,6 +173,9 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
} }
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
for (; ip <= ip_to; ip++) { for (; ip <= ip_to; ip++) {
......
...@@ -180,6 +180,9 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -180,6 +180,9 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
} }
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
for (; ip <= ip_to; ip++) { for (; ip <= ip_to; ip++) {
......
...@@ -253,6 +253,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -253,6 +253,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
} }
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
ip2_to = ip2_from; ip2_to = ip2_from;
if (tb[IPSET_ATTR_IP2_TO]) { if (tb[IPSET_ATTR_IP2_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
......
...@@ -140,7 +140,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -140,7 +140,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; u32 ip = 0, ip_to = 0, ipn, n = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -188,6 +188,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -188,6 +188,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
if (ip + UINT_MAX == ip_to) if (ip + UINT_MAX == ip_to)
return -IPSET_ERR_HASH_RANGE; return -IPSET_ERR_HASH_RANGE;
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr);
n++;
} while (ipn++ < ip_to);
if (n > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
do { do {
......
...@@ -202,7 +202,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -202,7 +202,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; u32 ip = 0, ip_to = 0, ipn, n = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -256,6 +256,14 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -256,6 +256,14 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip, ip_to, e.cidr); ip_set_mask_from_to(ip, ip_to, e.cidr);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr);
n++;
} while (ipn++ < ip_to);
if (n > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) if (retried)
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
......
...@@ -168,7 +168,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -168,7 +168,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
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; u32 ip = 0, ip_to = 0;
u32 ip2 = 0, ip2_from = 0, ip2_to = 0; u32 ip2 = 0, ip2_from = 0, ip2_to = 0, ipn;
u64 n = 0, m = 0;
int ret; int ret;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -244,6 +245,19 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -244,6 +245,19 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]);
n++;
} while (ipn++ < ip_to);
ipn = ip2_from;
do {
ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]);
m++;
} while (ipn++ < ip2_to);
if (n*m > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) { if (retried) {
ip = ntohl(h->next.ip[0]); ip = ntohl(h->next.ip[0]);
......
...@@ -158,7 +158,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -158,7 +158,8 @@ 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; u32 port, port_to, p = 0, ip = 0, ip_to = 0, ipn;
u64 n = 0;
bool with_ports = false; bool with_ports = false;
u8 cidr; u8 cidr;
int ret; int ret;
...@@ -235,6 +236,14 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -235,6 +236,14 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip, ip_to, e.cidr + 1); ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &cidr);
n++;
} while (ipn++ < ip_to);
if (n*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) { if (retried) {
ip = ntohl(h->next.ip); ip = ntohl(h->next.ip);
......
...@@ -182,7 +182,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -182,7 +182,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
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, p = 0, port, port_to; u32 ip = 0, ip_to = 0, p = 0, port, port_to;
u32 ip2_from = 0, ip2_to = 0, ip2; u32 ip2_from = 0, ip2_to = 0, ip2, ipn;
u64 n = 0, m = 0;
bool with_ports = false; bool with_ports = false;
int ret; int ret;
...@@ -284,6 +285,19 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -284,6 +285,19 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} else { } else {
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
} }
ipn = ip;
do {
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]);
n++;
} while (ipn++ < ip_to);
ipn = ip2_from;
do {
ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]);
m++;
} while (ipn++ < ip2_to);
if (n*m*(port_to - port + 1) > IPSET_MAX_RANGE)
return -ERANGE;
if (retried) { if (retried) {
ip = ntohl(h->next.ip[0]); ip = ntohl(h->next.ip[0]);
......
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