netfilter: ipset: Limit the maximal range of consecutive elements to add/delete
[ Upstream commit 5f7b51bf09baca8e4f80cbe879536842bafb5f31 ] 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: Brad Spengler <spender@grsecurity.net> Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Stable-dep-of: c7aa1a76d4a0 ("netfilter: ipset: regression in ip_set_hash_ip.c") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
8dca384970
commit
e62e62ea91
@ -198,6 +198,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 core set type structure */
|
/* The core set type structure */
|
||||||
struct ip_set_type {
|
struct ip_set_type {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
@ -131,8 +131,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]);
|
||||||
|
|
||||||
@ -143,6 +146,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);
|
||||||
|
@ -120,6 +120,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])) {
|
||||||
@ -132,8 +134,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]);
|
||||||
|
|
||||||
@ -142,6 +147,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++) {
|
||||||
|
@ -172,6 +172,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++) {
|
||||||
|
@ -179,6 +179,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++) {
|
||||||
|
@ -252,6 +252,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);
|
||||||
|
@ -139,7 +139,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])
|
||||||
@ -187,6 +187,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 {
|
||||||
|
@ -201,7 +201,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])
|
||||||
@ -255,6 +255,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);
|
||||||
|
@ -167,7 +167,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])
|
||||||
@ -243,6 +244,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]);
|
||||||
|
@ -157,7 +157,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;
|
||||||
@ -234,6 +235,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);
|
||||||
|
@ -181,7 +181,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;
|
||||||
|
|
||||||
@ -283,6 +284,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]);
|
||||||
|
Loading…
Reference in New Issue
Block a user