add patch to fix ipset memory exhaustion
[pve-kernel.git] / patches / kernel / 0010-netfilter-ipset-Fix-wraparound-n-hash-net-types.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3 Date: Fri, 12 Jan 2018 11:16:50 +0100
4 Subject: [PATCH] netfilter: ipset: Fix wraparound in hash:*net* types
5
6 Fix wraparound bug which could lead to memory exhaustion when adding an
7 x.x.x.x-255.255.255.255 range to any hash:*net* types.
8
9 Fixes Netfilter's bugzilla id #1212, reported by Thomas Schwark.
10
11 Fixes: 48596a8ddc46 ("netfilter: ipset: Fix adding an IPv4 range containing more than 2^31 addresses")
12 Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
13 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
14 ---
15 net/netfilter/ipset/ip_set_hash_ipportnet.c | 26 ++++++++++-----------
16 net/netfilter/ipset/ip_set_hash_net.c | 9 ++++---
17 net/netfilter/ipset/ip_set_hash_netiface.c | 9 ++++---
18 net/netfilter/ipset/ip_set_hash_netnet.c | 28 +++++++++++-----------
19 net/netfilter/ipset/ip_set_hash_netport.c | 19 ++++++++-------
20 net/netfilter/ipset/ip_set_hash_netportnet.c | 35 ++++++++++++++--------------
21 6 files changed, 63 insertions(+), 63 deletions(-)
22
23 diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
24 index 0f164e986bf1..88b83d6d3084 100644
25 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
26 +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
27 @@ -168,7 +168,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
28 struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
29 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
30 u32 ip = 0, ip_to = 0, p = 0, port, port_to;
31 - u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
32 + u32 ip2_from = 0, ip2_to = 0, ip2;
33 bool with_ports = false;
34 u8 cidr;
35 int ret;
36 @@ -269,22 +269,21 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
37 ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
38 }
39
40 - if (retried)
41 + if (retried) {
42 ip = ntohl(h->next.ip);
43 + p = ntohs(h->next.port);
44 + ip2 = ntohl(h->next.ip2);
45 + } else {
46 + p = port;
47 + ip2 = ip2_from;
48 + }
49 for (; ip <= ip_to; ip++) {
50 e.ip = htonl(ip);
51 - p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
52 - : port;
53 for (; p <= port_to; p++) {
54 e.port = htons(p);
55 - ip2 = retried &&
56 - ip == ntohl(h->next.ip) &&
57 - p == ntohs(h->next.port)
58 - ? ntohl(h->next.ip2) : ip2_from;
59 - while (ip2 <= ip2_to) {
60 + do {
61 e.ip2 = htonl(ip2);
62 - ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
63 - &cidr);
64 + ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr);
65 e.cidr = cidr - 1;
66 ret = adtfn(set, &e, &ext, &ext, flags);
67
68 @@ -292,9 +291,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
69 return ret;
70
71 ret = 0;
72 - ip2 = ip2_last + 1;
73 - }
74 + } while (ip2++ < ip2_to);
75 + ip2 = ip2_from;
76 }
77 + p = port;
78 }
79 return ret;
80 }
81 diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
82 index 1c67a1761e45..5449e23af13a 100644
83 --- a/net/netfilter/ipset/ip_set_hash_net.c
84 +++ b/net/netfilter/ipset/ip_set_hash_net.c
85 @@ -143,7 +143,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
86 ipset_adtfn adtfn = set->variant->adt[adt];
87 struct hash_net4_elem e = { .cidr = HOST_MASK };
88 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
89 - u32 ip = 0, ip_to = 0, last;
90 + u32 ip = 0, ip_to = 0;
91 int ret;
92
93 if (tb[IPSET_ATTR_LINENO])
94 @@ -193,16 +193,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
95 }
96 if (retried)
97 ip = ntohl(h->next.ip);
98 - while (ip <= ip_to) {
99 + do {
100 e.ip = htonl(ip);
101 - last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
102 + ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
103 ret = adtfn(set, &e, &ext, &ext, flags);
104 if (ret && !ip_set_eexist(ret, flags))
105 return ret;
106
107 ret = 0;
108 - ip = last + 1;
109 - }
110 + } while (ip++ < ip_to);
111 return ret;
112 }
113
114 diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
115 index d417074f1c1a..f5164c1efce2 100644
116 --- a/net/netfilter/ipset/ip_set_hash_netiface.c
117 +++ b/net/netfilter/ipset/ip_set_hash_netiface.c
118 @@ -200,7 +200,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
119 ipset_adtfn adtfn = set->variant->adt[adt];
120 struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
121 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
122 - u32 ip = 0, ip_to = 0, last;
123 + u32 ip = 0, ip_to = 0;
124 int ret;
125
126 if (tb[IPSET_ATTR_LINENO])
127 @@ -255,17 +255,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
128
129 if (retried)
130 ip = ntohl(h->next.ip);
131 - while (ip <= ip_to) {
132 + do {
133 e.ip = htonl(ip);
134 - last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
135 + ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
136 ret = adtfn(set, &e, &ext, &ext, flags);
137
138 if (ret && !ip_set_eexist(ret, flags))
139 return ret;
140
141 ret = 0;
142 - ip = last + 1;
143 - }
144 + } while (ip++ < ip_to);
145 return ret;
146 }
147
148 diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c
149 index 7f9ae2e9645b..5a2b923bd81f 100644
150 --- a/net/netfilter/ipset/ip_set_hash_netnet.c
151 +++ b/net/netfilter/ipset/ip_set_hash_netnet.c
152 @@ -169,8 +169,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
153 ipset_adtfn adtfn = set->variant->adt[adt];
154 struct hash_netnet4_elem e = { };
155 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
156 - u32 ip = 0, ip_to = 0, last;
157 - u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2;
158 + u32 ip = 0, ip_to = 0;
159 + u32 ip2 = 0, ip2_from = 0, ip2_to = 0;
160 int ret;
161
162 if (tb[IPSET_ATTR_LINENO])
163 @@ -247,27 +247,27 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
164 ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
165 }
166
167 - if (retried)
168 + if (retried) {
169 ip = ntohl(h->next.ip[0]);
170 + ip2 = ntohl(h->next.ip[1]);
171 + } else {
172 + ip2 = ip2_from;
173 + }
174
175 - while (ip <= ip_to) {
176 + do {
177 e.ip[0] = htonl(ip);
178 - last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
179 - ip2 = (retried &&
180 - ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
181 - : ip2_from;
182 - while (ip2 <= ip2_to) {
183 + ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
184 + do {
185 e.ip[1] = htonl(ip2);
186 - last2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
187 + ip2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
188 ret = adtfn(set, &e, &ext, &ext, flags);
189 if (ret && !ip_set_eexist(ret, flags))
190 return ret;
191
192 ret = 0;
193 - ip2 = last2 + 1;
194 - }
195 - ip = last + 1;
196 - }
197 + } while (ip2++ < ip2_to);
198 + ip2 = ip2_from;
199 + } while (ip++ < ip_to);
200 return ret;
201 }
202
203 diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
204 index e6ef382febe4..1a187be9ebc8 100644
205 --- a/net/netfilter/ipset/ip_set_hash_netport.c
206 +++ b/net/netfilter/ipset/ip_set_hash_netport.c
207 @@ -161,7 +161,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
208 ipset_adtfn adtfn = set->variant->adt[adt];
209 struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
210 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
211 - u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
212 + u32 port, port_to, p = 0, ip = 0, ip_to = 0;
213 bool with_ports = false;
214 u8 cidr;
215 int ret;
216 @@ -239,25 +239,26 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
217 ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
218 }
219
220 - if (retried)
221 + if (retried) {
222 ip = ntohl(h->next.ip);
223 - while (ip <= ip_to) {
224 + p = ntohs(h->next.port);
225 + } else {
226 + p = port;
227 + }
228 + do {
229 e.ip = htonl(ip);
230 - last = ip_set_range_to_cidr(ip, ip_to, &cidr);
231 + ip = ip_set_range_to_cidr(ip, ip_to, &cidr);
232 e.cidr = cidr - 1;
233 - p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
234 - : port;
235 for (; p <= port_to; p++) {
236 e.port = htons(p);
237 ret = adtfn(set, &e, &ext, &ext, flags);
238 -
239 if (ret && !ip_set_eexist(ret, flags))
240 return ret;
241
242 ret = 0;
243 }
244 - ip = last + 1;
245 - }
246 + p = port;
247 + } while (ip++ < ip_to);
248 return ret;
249 }
250
251 diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c
252 index 8602f2595a1a..d391485a6acd 100644
253 --- a/net/netfilter/ipset/ip_set_hash_netportnet.c
254 +++ b/net/netfilter/ipset/ip_set_hash_netportnet.c
255 @@ -184,8 +184,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
256 ipset_adtfn adtfn = set->variant->adt[adt];
257 struct hash_netportnet4_elem e = { };
258 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
259 - u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to;
260 - u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
261 + u32 ip = 0, ip_to = 0, p = 0, port, port_to;
262 + u32 ip2_from = 0, ip2_to = 0, ip2;
263 bool with_ports = false;
264 int ret;
265
266 @@ -288,33 +288,34 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
267 ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
268 }
269
270 - if (retried)
271 + if (retried) {
272 ip = ntohl(h->next.ip[0]);
273 + p = ntohs(h->next.port);
274 + ip2 = ntohl(h->next.ip[1]);
275 + } else {
276 + p = port;
277 + ip2 = ip2_from;
278 + }
279
280 - while (ip <= ip_to) {
281 + do {
282 e.ip[0] = htonl(ip);
283 - ip_last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
284 - p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
285 - : port;
286 + ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
287 for (; p <= port_to; p++) {
288 e.port = htons(p);
289 - ip2 = (retried && ip == ntohl(h->next.ip[0]) &&
290 - p == ntohs(h->next.port)) ? ntohl(h->next.ip[1])
291 - : ip2_from;
292 - while (ip2 <= ip2_to) {
293 + do {
294 e.ip[1] = htonl(ip2);
295 - ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
296 - &e.cidr[1]);
297 + ip2 = ip_set_range_to_cidr(ip2, ip2_to,
298 + &e.cidr[1]);
299 ret = adtfn(set, &e, &ext, &ext, flags);
300 if (ret && !ip_set_eexist(ret, flags))
301 return ret;
302
303 ret = 0;
304 - ip2 = ip2_last + 1;
305 - }
306 + } while (ip2++ < ip2_to);
307 + ip2 = ip2_from;
308 }
309 - ip = ip_last + 1;
310 - }
311 + p = port;
312 + } while (ip++ < ip_to);
313 return ret;
314 }
315
316 --
317 2.11.0
318