Skip to content

Commit 5f7b51b

Browse files
Jozsef Kadlecsikummakynes
authored andcommitted
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: Brad Spengler <spender@grsecurity.net> Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent c7d1022 commit 5f7b51b

File tree

11 files changed

+88
-7
lines changed

11 files changed

+88
-7
lines changed

include/linux/netfilter/ipset/ip_set.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ struct ip_set_region {
196196
u32 elements; /* Number of elements vs timeout */
197197
};
198198

199+
/* Max range where every element is added/deleted in one step */
200+
#define IPSET_MAX_RANGE (1<<20)
201+
199202
/* The max revision number supported by any set type + 1 */
200203
#define IPSET_REVISION_MAX 9
201204

net/netfilter/ipset/ip_set_hash_ip.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,11 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
132132
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
133133
if (ret)
134134
return ret;
135-
if (ip > ip_to)
135+
if (ip > ip_to) {
136+
if (ip_to == 0)
137+
return -IPSET_ERR_HASH_ELEM;
136138
swap(ip, ip_to);
139+
}
137140
} else if (tb[IPSET_ATTR_CIDR]) {
138141
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
139142

@@ -144,6 +147,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
144147

145148
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
146149

150+
/* 64bit division is not allowed on 32bit */
151+
if (((u64)ip_to - ip + 1) >> (32 - h->netmask) > IPSET_MAX_RANGE)
152+
return -ERANGE;
153+
147154
if (retried) {
148155
ip = ntohl(h->next.ip);
149156
e.ip = htonl(ip);

net/netfilter/ipset/ip_set_hash_ipmark.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
121121

122122
e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK]));
123123
e.mark &= h->markmask;
124+
if (e.mark == 0 && e.ip == 0)
125+
return -IPSET_ERR_HASH_ELEM;
124126

125127
if (adt == IPSET_TEST ||
126128
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) {
@@ -133,8 +135,11 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
133135
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
134136
if (ret)
135137
return ret;
136-
if (ip > ip_to)
138+
if (ip > ip_to) {
139+
if (e.mark == 0 && ip_to == 0)
140+
return -IPSET_ERR_HASH_ELEM;
137141
swap(ip, ip_to);
142+
}
138143
} else if (tb[IPSET_ATTR_CIDR]) {
139144
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
140145

@@ -143,6 +148,9 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
143148
ip_set_mask_from_to(ip, ip_to, cidr);
144149
}
145150

151+
if (((u64)ip_to - ip + 1) > IPSET_MAX_RANGE)
152+
return -ERANGE;
153+
146154
if (retried)
147155
ip = ntohl(h->next.ip);
148156
for (; ip <= ip_to; ip++) {

net/netfilter/ipset/ip_set_hash_ipport.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
173173
swap(port, port_to);
174174
}
175175

176+
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
177+
return -ERANGE;
178+
176179
if (retried)
177180
ip = ntohl(h->next.ip);
178181
for (; ip <= ip_to; ip++) {

net/netfilter/ipset/ip_set_hash_ipportip.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
180180
swap(port, port_to);
181181
}
182182

183+
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
184+
return -ERANGE;
185+
183186
if (retried)
184187
ip = ntohl(h->next.ip);
185188
for (; ip <= ip_to; ip++) {

net/netfilter/ipset/ip_set_hash_ipportnet.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
253253
swap(port, port_to);
254254
}
255255

256+
if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE)
257+
return -ERANGE;
258+
256259
ip2_to = ip2_from;
257260
if (tb[IPSET_ATTR_IP2_TO]) {
258261
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);

net/netfilter/ipset/ip_set_hash_net.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
140140
ipset_adtfn adtfn = set->variant->adt[adt];
141141
struct hash_net4_elem e = { .cidr = HOST_MASK };
142142
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
143-
u32 ip = 0, ip_to = 0;
143+
u32 ip = 0, ip_to = 0, ipn, n = 0;
144144
int ret;
145145

146146
if (tb[IPSET_ATTR_LINENO])
@@ -188,6 +188,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
188188
if (ip + UINT_MAX == ip_to)
189189
return -IPSET_ERR_HASH_RANGE;
190190
}
191+
ipn = ip;
192+
do {
193+
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr);
194+
n++;
195+
} while (ipn++ < ip_to);
196+
197+
if (n > IPSET_MAX_RANGE)
198+
return -ERANGE;
199+
191200
if (retried)
192201
ip = ntohl(h->next.ip);
193202
do {

net/netfilter/ipset/ip_set_hash_netiface.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
202202
ipset_adtfn adtfn = set->variant->adt[adt];
203203
struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
204204
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
205-
u32 ip = 0, ip_to = 0;
205+
u32 ip = 0, ip_to = 0, ipn, n = 0;
206206
int ret;
207207

208208
if (tb[IPSET_ATTR_LINENO])
@@ -256,6 +256,14 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
256256
} else {
257257
ip_set_mask_from_to(ip, ip_to, e.cidr);
258258
}
259+
ipn = ip;
260+
do {
261+
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr);
262+
n++;
263+
} while (ipn++ < ip_to);
264+
265+
if (n > IPSET_MAX_RANGE)
266+
return -ERANGE;
259267

260268
if (retried)
261269
ip = ntohl(h->next.ip);

net/netfilter/ipset/ip_set_hash_netnet.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
168168
struct hash_netnet4_elem e = { };
169169
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
170170
u32 ip = 0, ip_to = 0;
171-
u32 ip2 = 0, ip2_from = 0, ip2_to = 0;
171+
u32 ip2 = 0, ip2_from = 0, ip2_to = 0, ipn;
172+
u64 n = 0, m = 0;
172173
int ret;
173174

174175
if (tb[IPSET_ATTR_LINENO])
@@ -244,6 +245,19 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
244245
} else {
245246
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
246247
}
248+
ipn = ip;
249+
do {
250+
ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]);
251+
n++;
252+
} while (ipn++ < ip_to);
253+
ipn = ip2_from;
254+
do {
255+
ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]);
256+
m++;
257+
} while (ipn++ < ip2_to);
258+
259+
if (n*m > IPSET_MAX_RANGE)
260+
return -ERANGE;
247261

248262
if (retried) {
249263
ip = ntohl(h->next.ip[0]);

net/netfilter/ipset/ip_set_hash_netport.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
158158
ipset_adtfn adtfn = set->variant->adt[adt];
159159
struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
160160
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
161-
u32 port, port_to, p = 0, ip = 0, ip_to = 0;
161+
u32 port, port_to, p = 0, ip = 0, ip_to = 0, ipn;
162+
u64 n = 0;
162163
bool with_ports = false;
163164
u8 cidr;
164165
int ret;
@@ -235,6 +236,14 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
235236
} else {
236237
ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
237238
}
239+
ipn = ip;
240+
do {
241+
ipn = ip_set_range_to_cidr(ipn, ip_to, &cidr);
242+
n++;
243+
} while (ipn++ < ip_to);
244+
245+
if (n*(port_to - port + 1) > IPSET_MAX_RANGE)
246+
return -ERANGE;
238247

239248
if (retried) {
240249
ip = ntohl(h->next.ip);

0 commit comments

Comments
 (0)