Skip to content

Commit b9a4072

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for your net tree, they are: 1) Fix OOM that syskaller triggers with ipt_replace.size = -1 and IPT_SO_SET_REPLACE socket option, from Dmitry Vyukov. 2) Check for too long extension name in xt_request_find_{match|target} that result in out-of-bound reads, from Eric Dumazet. 3) Fix memory exhaustion bug in ipset hash:*net* types when adding ranges that look like x.x.x.x-255.255.255.255, from Jozsef Kadlecsik. 4) Fix pointer leaks to userspace in x_tables, from Dmitry Vyukov. 5) Insufficient sanity checks in clusterip_tg_check(), also from Dmitry. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7973bfd + 3f34cfa commit b9a4072

17 files changed

+114
-99
lines changed

net/ipv4/ip_sockglue.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,11 +1255,8 @@ int ip_setsockopt(struct sock *sk, int level,
12551255
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
12561256
optname != IP_IPSEC_POLICY &&
12571257
optname != IP_XFRM_POLICY &&
1258-
!ip_mroute_opt(optname)) {
1259-
lock_sock(sk);
1258+
!ip_mroute_opt(optname))
12601259
err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
1261-
release_sock(sk);
1262-
}
12631260
#endif
12641261
return err;
12651262
}
@@ -1284,12 +1281,9 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
12841281
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
12851282
optname != IP_IPSEC_POLICY &&
12861283
optname != IP_XFRM_POLICY &&
1287-
!ip_mroute_opt(optname)) {
1288-
lock_sock(sk);
1289-
err = compat_nf_setsockopt(sk, PF_INET, optname,
1290-
optval, optlen);
1291-
release_sock(sk);
1292-
}
1284+
!ip_mroute_opt(optname))
1285+
err = compat_nf_setsockopt(sk, PF_INET, optname, optval,
1286+
optlen);
12931287
#endif
12941288
return err;
12951289
}

net/ipv4/netfilter/ipt_CLUSTERIP.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
431431
struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
432432
const struct ipt_entry *e = par->entryinfo;
433433
struct clusterip_config *config;
434-
int ret;
434+
int ret, i;
435435

436436
if (par->nft_compat) {
437437
pr_err("cannot use CLUSTERIP target from nftables compat\n");
@@ -450,8 +450,18 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
450450
pr_info("Please specify destination IP\n");
451451
return -EINVAL;
452452
}
453-
454-
/* FIXME: further sanity checks */
453+
if (cipinfo->num_local_nodes > ARRAY_SIZE(cipinfo->local_nodes)) {
454+
pr_info("bad num_local_nodes %u\n", cipinfo->num_local_nodes);
455+
return -EINVAL;
456+
}
457+
for (i = 0; i < cipinfo->num_local_nodes; i++) {
458+
if (cipinfo->local_nodes[i] - 1 >=
459+
sizeof(config->local_nodes) * 8) {
460+
pr_info("bad local_nodes[%d] %u\n",
461+
i, cipinfo->local_nodes[i]);
462+
return -EINVAL;
463+
}
464+
}
455465

456466
config = clusterip_config_find_get(par->net, e->ip.dst.s_addr, 1);
457467
if (!config) {

net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,19 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
213213
struct nf_conntrack_tuple tuple;
214214

215215
memset(&tuple, 0, sizeof(tuple));
216+
217+
lock_sock(sk);
216218
tuple.src.u3.ip = inet->inet_rcv_saddr;
217219
tuple.src.u.tcp.port = inet->inet_sport;
218220
tuple.dst.u3.ip = inet->inet_daddr;
219221
tuple.dst.u.tcp.port = inet->inet_dport;
220222
tuple.src.l3num = PF_INET;
221223
tuple.dst.protonum = sk->sk_protocol;
224+
release_sock(sk);
222225

223226
/* We only do TCP and SCTP at the moment: is there a better way? */
224-
if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) {
227+
if (tuple.dst.protonum != IPPROTO_TCP &&
228+
tuple.dst.protonum != IPPROTO_SCTP) {
225229
pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
226230
return -ENOPROTOOPT;
227231
}

net/ipv6/ipv6_sockglue.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -923,12 +923,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
923923
#ifdef CONFIG_NETFILTER
924924
/* we need to exclude all possible ENOPROTOOPTs except default case */
925925
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
926-
optname != IPV6_XFRM_POLICY) {
927-
lock_sock(sk);
928-
err = nf_setsockopt(sk, PF_INET6, optname, optval,
929-
optlen);
930-
release_sock(sk);
931-
}
926+
optname != IPV6_XFRM_POLICY)
927+
err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
932928
#endif
933929
return err;
934930
}
@@ -958,12 +954,9 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
958954
#ifdef CONFIG_NETFILTER
959955
/* we need to exclude all possible ENOPROTOOPTs except default case */
960956
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
961-
optname != IPV6_XFRM_POLICY) {
962-
lock_sock(sk);
963-
err = compat_nf_setsockopt(sk, PF_INET6, optname,
964-
optval, optlen);
965-
release_sock(sk);
966-
}
957+
optname != IPV6_XFRM_POLICY)
958+
err = compat_nf_setsockopt(sk, PF_INET6, optname, optval,
959+
optlen);
967960
#endif
968961
return err;
969962
}

net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,27 @@ static const struct nf_hook_ops ipv6_conntrack_ops[] = {
221221
static int
222222
ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
223223
{
224-
const struct inet_sock *inet = inet_sk(sk);
224+
struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
225225
const struct ipv6_pinfo *inet6 = inet6_sk(sk);
226+
const struct inet_sock *inet = inet_sk(sk);
226227
const struct nf_conntrack_tuple_hash *h;
227228
struct sockaddr_in6 sin6;
228-
struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
229229
struct nf_conn *ct;
230+
__be32 flow_label;
231+
int bound_dev_if;
230232

233+
lock_sock(sk);
231234
tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
232235
tuple.src.u.tcp.port = inet->inet_sport;
233236
tuple.dst.u3.in6 = sk->sk_v6_daddr;
234237
tuple.dst.u.tcp.port = inet->inet_dport;
235238
tuple.dst.protonum = sk->sk_protocol;
239+
bound_dev_if = sk->sk_bound_dev_if;
240+
flow_label = inet6->flow_label;
241+
release_sock(sk);
236242

237-
if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP)
243+
if (tuple.dst.protonum != IPPROTO_TCP &&
244+
tuple.dst.protonum != IPPROTO_SCTP)
238245
return -ENOPROTOOPT;
239246

240247
if (*len < 0 || (unsigned int) *len < sizeof(sin6))
@@ -252,14 +259,13 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
252259

253260
sin6.sin6_family = AF_INET6;
254261
sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
255-
sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK;
262+
sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
256263
memcpy(&sin6.sin6_addr,
257264
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
258265
sizeof(sin6.sin6_addr));
259266

260267
nf_ct_put(ct);
261-
sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
262-
sk->sk_bound_dev_if);
268+
sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
263269
return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
264270
}
265271

net/netfilter/ipset/ip_set_hash_ipportnet.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
168168
struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
169169
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
170170
u32 ip = 0, ip_to = 0, p = 0, port, port_to;
171-
u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
171+
u32 ip2_from = 0, ip2_to = 0, ip2;
172172
bool with_ports = false;
173173
u8 cidr;
174174
int ret;
@@ -269,32 +269,32 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
269269
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
270270
}
271271

272-
if (retried)
272+
if (retried) {
273273
ip = ntohl(h->next.ip);
274+
p = ntohs(h->next.port);
275+
ip2 = ntohl(h->next.ip2);
276+
} else {
277+
p = port;
278+
ip2 = ip2_from;
279+
}
274280
for (; ip <= ip_to; ip++) {
275281
e.ip = htonl(ip);
276-
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
277-
: port;
278282
for (; p <= port_to; p++) {
279283
e.port = htons(p);
280-
ip2 = retried &&
281-
ip == ntohl(h->next.ip) &&
282-
p == ntohs(h->next.port)
283-
? ntohl(h->next.ip2) : ip2_from;
284-
while (ip2 <= ip2_to) {
284+
do {
285285
e.ip2 = htonl(ip2);
286-
ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
287-
&cidr);
286+
ip2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr);
288287
e.cidr = cidr - 1;
289288
ret = adtfn(set, &e, &ext, &ext, flags);
290289

291290
if (ret && !ip_set_eexist(ret, flags))
292291
return ret;
293292

294293
ret = 0;
295-
ip2 = ip2_last + 1;
296-
}
294+
} while (ip2++ < ip2_to);
295+
ip2 = ip2_from;
297296
}
297+
p = port;
298298
}
299299
return ret;
300300
}

net/netfilter/ipset/ip_set_hash_net.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
143143
ipset_adtfn adtfn = set->variant->adt[adt];
144144
struct hash_net4_elem e = { .cidr = HOST_MASK };
145145
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
146-
u32 ip = 0, ip_to = 0, last;
146+
u32 ip = 0, ip_to = 0;
147147
int ret;
148148

149149
if (tb[IPSET_ATTR_LINENO])
@@ -193,16 +193,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
193193
}
194194
if (retried)
195195
ip = ntohl(h->next.ip);
196-
while (ip <= ip_to) {
196+
do {
197197
e.ip = htonl(ip);
198-
last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
198+
ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
199199
ret = adtfn(set, &e, &ext, &ext, flags);
200200
if (ret && !ip_set_eexist(ret, flags))
201201
return ret;
202202

203203
ret = 0;
204-
ip = last + 1;
205-
}
204+
} while (ip++ < ip_to);
206205
return ret;
207206
}
208207

net/netfilter/ipset/ip_set_hash_netiface.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
200200
ipset_adtfn adtfn = set->variant->adt[adt];
201201
struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
202202
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
203-
u32 ip = 0, ip_to = 0, last;
203+
u32 ip = 0, ip_to = 0;
204204
int ret;
205205

206206
if (tb[IPSET_ATTR_LINENO])
@@ -255,17 +255,16 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
255255

256256
if (retried)
257257
ip = ntohl(h->next.ip);
258-
while (ip <= ip_to) {
258+
do {
259259
e.ip = htonl(ip);
260-
last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
260+
ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
261261
ret = adtfn(set, &e, &ext, &ext, flags);
262262

263263
if (ret && !ip_set_eexist(ret, flags))
264264
return ret;
265265

266266
ret = 0;
267-
ip = last + 1;
268-
}
267+
} while (ip++ < ip_to);
269268
return ret;
270269
}
271270

net/netfilter/ipset/ip_set_hash_netnet.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
169169
ipset_adtfn adtfn = set->variant->adt[adt];
170170
struct hash_netnet4_elem e = { };
171171
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
172-
u32 ip = 0, ip_to = 0, last;
173-
u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2;
172+
u32 ip = 0, ip_to = 0;
173+
u32 ip2 = 0, ip2_from = 0, ip2_to = 0;
174174
int ret;
175175

176176
if (tb[IPSET_ATTR_LINENO])
@@ -247,27 +247,27 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
247247
ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
248248
}
249249

250-
if (retried)
250+
if (retried) {
251251
ip = ntohl(h->next.ip[0]);
252+
ip2 = ntohl(h->next.ip[1]);
253+
} else {
254+
ip2 = ip2_from;
255+
}
252256

253-
while (ip <= ip_to) {
257+
do {
254258
e.ip[0] = htonl(ip);
255-
last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
256-
ip2 = (retried &&
257-
ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
258-
: ip2_from;
259-
while (ip2 <= ip2_to) {
259+
ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
260+
do {
260261
e.ip[1] = htonl(ip2);
261-
last2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
262+
ip2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
262263
ret = adtfn(set, &e, &ext, &ext, flags);
263264
if (ret && !ip_set_eexist(ret, flags))
264265
return ret;
265266

266267
ret = 0;
267-
ip2 = last2 + 1;
268-
}
269-
ip = last + 1;
270-
}
268+
} while (ip2++ < ip2_to);
269+
ip2 = ip2_from;
270+
} while (ip++ < ip_to);
271271
return ret;
272272
}
273273

net/netfilter/ipset/ip_set_hash_netport.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
161161
ipset_adtfn adtfn = set->variant->adt[adt];
162162
struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
163163
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
164-
u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
164+
u32 port, port_to, p = 0, ip = 0, ip_to = 0;
165165
bool with_ports = false;
166166
u8 cidr;
167167
int ret;
@@ -239,25 +239,26 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
239239
ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
240240
}
241241

242-
if (retried)
242+
if (retried) {
243243
ip = ntohl(h->next.ip);
244-
while (ip <= ip_to) {
244+
p = ntohs(h->next.port);
245+
} else {
246+
p = port;
247+
}
248+
do {
245249
e.ip = htonl(ip);
246-
last = ip_set_range_to_cidr(ip, ip_to, &cidr);
250+
ip = ip_set_range_to_cidr(ip, ip_to, &cidr);
247251
e.cidr = cidr - 1;
248-
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
249-
: port;
250252
for (; p <= port_to; p++) {
251253
e.port = htons(p);
252254
ret = adtfn(set, &e, &ext, &ext, flags);
253-
254255
if (ret && !ip_set_eexist(ret, flags))
255256
return ret;
256257

257258
ret = 0;
258259
}
259-
ip = last + 1;
260-
}
260+
p = port;
261+
} while (ip++ < ip_to);
261262
return ret;
262263
}
263264

0 commit comments

Comments
 (0)