From: Jozsef Kadlecsik Date: Wed, 14 Jul 2021 10:37:07 +0000 (+0200) Subject: Limit the maximal range of consecutive elements to add/delete X-Git-Tag: v7.12~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=15932461c91e8aedf54e885d429b954b439605d2;p=thirdparty%2Fipset.git 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 Brad Spengler. Signed-off-by: Jozsef Kadlecsik --- diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h index 554f90fa..3a6963cd 100644 --- a/kernel/include/linux/netfilter/ipset/ip_set.h +++ b/kernel/include/linux/netfilter/ipset/ip_set.h @@ -199,6 +199,9 @@ struct ip_set_region { 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 */ #define IPSET_REVISION_MAX 9 diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ip.c b/kernel/net/netfilter/ipset/ip_set_hash_ip.c index 94e17a56..a3559d7d 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_ip.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_ip.c @@ -145,6 +145,9 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); + if ((ip_to - ip + 1)/hosts > IPSET_MAX_RANGE) + return -ERANGE; + if (retried) { ip = ntohl(h->next.ip); e.ip = htonl(ip); diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipmark.c b/kernel/net/netfilter/ipset/ip_set_hash_ipmark.c index 1757bf84..698da284 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_ipmark.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_ipmark.c @@ -145,6 +145,9 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], ip_set_mask_from_to(ip, ip_to, cidr); } + if ((ip_to - ip + 1) > IPSET_MAX_RANGE) + return -ERANGE; + if (retried) ip = ntohl(h->next.ip); for (; ip <= ip_to; ip++) { diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipport.c b/kernel/net/netfilter/ipset/ip_set_hash_ipport.c index b22f2809..36ffc3b8 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_ipport.c @@ -174,6 +174,9 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], swap(port, port_to); } + if ((ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE) + return -ERANGE; + if (retried) ip = ntohl(h->next.ip); for (; ip <= ip_to; ip++) { diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c index d3701519..0728b38d 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -181,6 +181,9 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], swap(port, port_to); } + if ((ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE) + return -ERANGE; + if (retried) ip = ntohl(h->next.ip); for (; ip <= ip_to; ip++) { diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c index 64f82f29..94dde471 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -247,6 +247,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ip_set_mask_from_to(ip, ip_to, cidr); } + if ((ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE) + return -ERANGE; + port_to = port = ntohs(e.port); if (tb[IPSET_ATTR_PORT_TO]) { port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); diff --git a/kernel/net/netfilter/ipset/ip_set_hash_net.c b/kernel/net/netfilter/ipset/ip_set_hash_net.c index 54318dd9..c2819c6f 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_net.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_net.c @@ -189,6 +189,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], if (ip + UINT_MAX == ip_to) return -IPSET_ERR_HASH_RANGE; } + if ((ip_to - ip + 1)/(1<<(32 - e.cidr)) > IPSET_MAX_RANGE) + return -ERANGE; if (retried) ip = ntohl(h->next.ip); do { diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c index 58332ead..4bebf2ad 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c @@ -257,6 +257,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], } else { ip_set_mask_from_to(ip, ip_to, e.cidr); } + if ((ip_to - ip + 1)/(1<<(32 - e.cidr)) > IPSET_MAX_RANGE) + return -ERANGE; if (retried) ip = ntohl(h->next.ip); diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netnet.c b/kernel/net/netfilter/ipset/ip_set_hash_netnet.c index 6532f050..4ca005dd 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_netnet.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_netnet.c @@ -244,6 +244,9 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], } else { ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); } + if ((ip_to - ip + 1)/(1<<(32 - e.cidr[0]))* + (ip2_to - ip2_from + 1)/(1<<(32 - e.cidr[1])) > IPSET_MAX_RANGE) + return -ERANGE; if (retried) { ip = ntohl(h->next.ip[0]); diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netportnet.c b/kernel/net/netfilter/ipset/ip_set_hash_netportnet.c index 070736d4..0bf866d4 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_netportnet.c +++ b/kernel/net/netfilter/ipset/ip_set_hash_netportnet.c @@ -285,6 +285,10 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], } else { ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); } + if ((ip_to - ip + 1)/(1<<(32 - e.cidr[0]))* + (ip2_to - ip2_from + 1)/(1<<(32 - e.cidr[1])) * + (port_to - port + 1) > IPSET_MAX_RANGE) + return -ERANGE; if (retried) { ip = ntohl(h->next.ip[0]); diff --git a/lib/errcode.c b/lib/errcode.c index b38f95e3..76bab742 100644 --- a/lib/errcode.c +++ b/lib/errcode.c @@ -25,6 +25,8 @@ static const struct ipset_errcode_table core_errcode_table[] = { "The set with the given name does not exist" }, { EMSGSIZE, 0, "Kernel error received: message could not be created" }, + { ERANGE, 0, + "The specified range is too large, split it up into smaller ranges" }, { IPSET_ERR_PROTOCOL, 0, "Kernel error received: ipset protocol error" },