Skip to content

Commit a31d47b

Browse files
Jozsef Kadlecsikummakynes
authored andcommitted
netfilter: ipset: fix hash:net,port,net hang with /0 subnet
The hash:net,port,net set type supports /0 subnets. However, the patch commit 5f7b51b titled "netfilter: ipset: Limit the maximal range of consecutive elements to add/delete" did not take into account it and resulted in an endless loop. The bug is actually older but the patch 5f7b51b brings it out earlier. Handle /0 subnets properly in hash:net,port,net set types. Fixes: 5f7b51b ("netfilter: ipset: Limit the maximal range of consecutive elements to add/delete") Reported-by: Марк Коренберг <socketpair@gmail.com> Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 123b996 commit a31d47b

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

net/netfilter/ipset/ip_set_hash_netportnet.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,26 @@ hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
173173
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
174174
}
175175

176+
static u32
177+
hash_netportnet4_range_to_cidr(u32 from, u32 to, u8 *cidr)
178+
{
179+
if (from == 0 && to == UINT_MAX) {
180+
*cidr = 0;
181+
return to;
182+
}
183+
return ip_set_range_to_cidr(from, to, cidr);
184+
}
185+
176186
static int
177187
hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
178188
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
179189
{
180-
const struct hash_netportnet4 *h = set->data;
190+
struct hash_netportnet4 *h = set->data;
181191
ipset_adtfn adtfn = set->variant->adt[adt];
182192
struct hash_netportnet4_elem e = { };
183193
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
184194
u32 ip = 0, ip_to = 0, p = 0, port, port_to;
185-
u32 ip2_from = 0, ip2_to = 0, ip2, ipn;
186-
u64 n = 0, m = 0;
195+
u32 ip2_from = 0, ip2_to = 0, ip2, i = 0;
187196
bool with_ports = false;
188197
int ret;
189198

@@ -285,19 +294,6 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
285294
} else {
286295
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
287296
}
288-
ipn = ip;
289-
do {
290-
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]);
291-
n++;
292-
} while (ipn++ < ip_to);
293-
ipn = ip2_from;
294-
do {
295-
ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]);
296-
m++;
297-
} while (ipn++ < ip2_to);
298-
299-
if (n*m*(port_to - port + 1) > IPSET_MAX_RANGE)
300-
return -ERANGE;
301297

302298
if (retried) {
303299
ip = ntohl(h->next.ip[0]);
@@ -310,13 +306,19 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
310306

311307
do {
312308
e.ip[0] = htonl(ip);
313-
ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
309+
ip = hash_netportnet4_range_to_cidr(ip, ip_to, &e.cidr[0]);
314310
for (; p <= port_to; p++) {
315311
e.port = htons(p);
316312
do {
313+
i++;
317314
e.ip[1] = htonl(ip2);
318-
ip2 = ip_set_range_to_cidr(ip2, ip2_to,
319-
&e.cidr[1]);
315+
if (i > IPSET_MAX_RANGE) {
316+
hash_netportnet4_data_next(&h->next,
317+
&e);
318+
return -ERANGE;
319+
}
320+
ip2 = hash_netportnet4_range_to_cidr(ip2,
321+
ip2_to, &e.cidr[1]);
320322
ret = adtfn(set, &e, &ext, &ext, flags);
321323
if (ret && !ip_set_eexist(ret, flags))
322324
return ret;

0 commit comments

Comments
 (0)