Skip to content

Commit 4a0c719

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter/IPVS fixes for net The following patchset contains Netfilter fixes for your net tree, they are: 1) Put back reference on CLUSTERIP configuration structure from the error path, patch from Florian Westphal. 2) Put reference on CLUSTERIP configuration instead of freeing it, another cpu may still be walking over it, also from Florian. 3) Refetch pointer to IPv6 header from nf_nat_ipv6_manip_pkt() given packet manipulation may reallocation the skbuff header, from Florian. 4) Missing match size sanity checks in ebt_among, from Florian. 5) Convert BUG_ON to WARN_ON in ebtables, from Florian. 6) Sanity check userspace offsets from ebtables kernel, from Florian. 7) Missing checksum replace call in flowtable IPv4 DNAT, from Felix Fietkau. 8) Bump the right stats on checksum error from bridge netfilter, from Taehee Yoo. 9) Unset interface flag in IPv6 fib lookups otherwise we get misleading routing lookup results, from Florian. 10) Missing sk_to_full_sk() in ip6_route_me_harder() from Eric Dumazet. 11) Don't allow devices to be part of multiple flowtables at the same time, this may break setups. 12) Missing netlink attribute validation in flowtable deletion. 13) Wrong array index in nf_unregister_net_hook() call from error path in flowtable addition path. 14) Fix FTP IPVS helper when NAT mangling is in place, patch from Julian Anastasov. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents d69242b + 8a949ff commit 4a0c719

File tree

11 files changed

+98
-39
lines changed

11 files changed

+98
-39
lines changed

net/bridge/br_netfilter_hooks.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb)
214214

215215
iph = ip_hdr(skb);
216216
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
217-
goto inhdr_error;
217+
goto csum_error;
218218

219219
len = ntohs(iph->tot_len);
220220
if (skb->len < len) {
@@ -236,6 +236,8 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb)
236236
*/
237237
return 0;
238238

239+
csum_error:
240+
__IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS);
239241
inhdr_error:
240242
__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
241243
drop:

net/bridge/netfilter/ebt_among.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,35 @@ ebt_among_mt(const struct sk_buff *skb, struct xt_action_param *par)
172172
return true;
173173
}
174174

175+
static bool poolsize_invalid(const struct ebt_mac_wormhash *w)
176+
{
177+
return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple));
178+
}
179+
175180
static int ebt_among_mt_check(const struct xt_mtchk_param *par)
176181
{
177182
const struct ebt_among_info *info = par->matchinfo;
178183
const struct ebt_entry_match *em =
179184
container_of(par->matchinfo, const struct ebt_entry_match, data);
180-
int expected_length = sizeof(struct ebt_among_info);
185+
unsigned int expected_length = sizeof(struct ebt_among_info);
181186
const struct ebt_mac_wormhash *wh_dst, *wh_src;
182187
int err;
183188

189+
if (expected_length > em->match_size)
190+
return -EINVAL;
191+
184192
wh_dst = ebt_among_wh_dst(info);
185-
wh_src = ebt_among_wh_src(info);
193+
if (poolsize_invalid(wh_dst))
194+
return -EINVAL;
195+
186196
expected_length += ebt_mac_wormhash_size(wh_dst);
197+
if (expected_length > em->match_size)
198+
return -EINVAL;
199+
200+
wh_src = ebt_among_wh_src(info);
201+
if (poolsize_invalid(wh_src))
202+
return -EINVAL;
203+
187204
expected_length += ebt_mac_wormhash_size(wh_src);
188205

189206
if (em->match_size != EBT_ALIGN(expected_length)) {

net/bridge/netfilter/ebtables.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,8 @@ static int compat_match_to_user(struct ebt_entry_match *m, void __user **dstptr,
16411641
int off = ebt_compat_match_offset(match, m->match_size);
16421642
compat_uint_t msize = m->match_size - off;
16431643

1644-
BUG_ON(off >= m->match_size);
1644+
if (WARN_ON(off >= m->match_size))
1645+
return -EINVAL;
16451646

16461647
if (copy_to_user(cm->u.name, match->name,
16471648
strlen(match->name) + 1) || put_user(msize, &cm->match_size))
@@ -1671,7 +1672,8 @@ static int compat_target_to_user(struct ebt_entry_target *t,
16711672
int off = xt_compat_target_offset(target);
16721673
compat_uint_t tsize = t->target_size - off;
16731674

1674-
BUG_ON(off >= t->target_size);
1675+
if (WARN_ON(off >= t->target_size))
1676+
return -EINVAL;
16751677

16761678
if (copy_to_user(cm->u.name, target->name,
16771679
strlen(target->name) + 1) || put_user(tsize, &cm->match_size))
@@ -1902,7 +1904,8 @@ static int ebt_buf_add(struct ebt_entries_buf_state *state,
19021904
if (state->buf_kern_start == NULL)
19031905
goto count_only;
19041906

1905-
BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len);
1907+
if (WARN_ON(state->buf_kern_offset + sz > state->buf_kern_len))
1908+
return -EINVAL;
19061909

19071910
memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz);
19081911

@@ -1915,7 +1918,8 @@ static int ebt_buf_add_pad(struct ebt_entries_buf_state *state, unsigned int sz)
19151918
{
19161919
char *b = state->buf_kern_start;
19171920

1918-
BUG_ON(b && state->buf_kern_offset > state->buf_kern_len);
1921+
if (WARN_ON(b && state->buf_kern_offset > state->buf_kern_len))
1922+
return -EINVAL;
19191923

19201924
if (b != NULL && sz > 0)
19211925
memset(b + state->buf_kern_offset, 0, sz);
@@ -1992,8 +1996,10 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
19921996
pad = XT_ALIGN(size_kern) - size_kern;
19931997

19941998
if (pad > 0 && dst) {
1995-
BUG_ON(state->buf_kern_len <= pad);
1996-
BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad);
1999+
if (WARN_ON(state->buf_kern_len <= pad))
2000+
return -EINVAL;
2001+
if (WARN_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad))
2002+
return -EINVAL;
19972003
memset(dst + size_kern, 0, pad);
19982004
}
19992005
return off + match_size;
@@ -2043,7 +2049,8 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
20432049
if (ret < 0)
20442050
return ret;
20452051

2046-
BUG_ON(ret < match32->match_size);
2052+
if (WARN_ON(ret < match32->match_size))
2053+
return -EINVAL;
20472054
growth += ret - match32->match_size;
20482055
growth += ebt_compat_entry_padsize();
20492056

@@ -2053,7 +2060,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
20532060
if (match_kern)
20542061
match_kern->match_size = ret;
20552062

2056-
WARN_ON(type == EBT_COMPAT_TARGET && size_left);
2063+
if (WARN_ON(type == EBT_COMPAT_TARGET && size_left))
2064+
return -EINVAL;
2065+
20572066
match32 = (struct compat_ebt_entry_mwt *) buf;
20582067
}
20592068

@@ -2109,6 +2118,15 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
21092118
*
21102119
* offsets are relative to beginning of struct ebt_entry (i.e., 0).
21112120
*/
2121+
for (i = 0; i < 4 ; ++i) {
2122+
if (offsets[i] >= *total)
2123+
return -EINVAL;
2124+
if (i == 0)
2125+
continue;
2126+
if (offsets[i-1] > offsets[i])
2127+
return -EINVAL;
2128+
}
2129+
21122130
for (i = 0, j = 1 ; j < 4 ; j++, i++) {
21132131
struct compat_ebt_entry_mwt *match32;
21142132
unsigned int size;
@@ -2140,7 +2158,8 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
21402158

21412159
startoff = state->buf_user_offset - startoff;
21422160

2143-
BUG_ON(*total < startoff);
2161+
if (WARN_ON(*total < startoff))
2162+
return -EINVAL;
21442163
*total -= startoff;
21452164
return 0;
21462165
}
@@ -2267,7 +2286,8 @@ static int compat_do_replace(struct net *net, void __user *user,
22672286
state.buf_kern_len = size64;
22682287

22692288
ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
2270-
BUG_ON(ret < 0); /* parses same data again */
2289+
if (WARN_ON(ret < 0))
2290+
goto out_unlock;
22712291

22722292
vfree(entries_tmp);
22732293
tmp.entries_size = size64;

net/ipv4/netfilter/ipt_CLUSTERIP.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,6 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
232232
c->hash_mode = i->hash_mode;
233233
c->hash_initval = i->hash_initval;
234234
refcount_set(&c->refcount, 1);
235-
refcount_set(&c->entries, 1);
236235

237236
spin_lock_bh(&cn->lock);
238237
if (__clusterip_config_find(net, ip)) {
@@ -263,8 +262,10 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
263262

264263
c->notifier.notifier_call = clusterip_netdev_event;
265264
err = register_netdevice_notifier(&c->notifier);
266-
if (!err)
265+
if (!err) {
266+
refcount_set(&c->entries, 1);
267267
return c;
268+
}
268269

269270
#ifdef CONFIG_PROC_FS
270271
proc_remove(c->pde);
@@ -273,7 +274,7 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
273274
spin_lock_bh(&cn->lock);
274275
list_del_rcu(&c->list);
275276
spin_unlock_bh(&cn->lock);
276-
kfree(c);
277+
clusterip_config_put(c);
277278

278279
return ERR_PTR(err);
279280
}
@@ -496,19 +497,23 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
496497
return PTR_ERR(config);
497498
}
498499
}
499-
cipinfo->config = config;
500500

501501
ret = nf_ct_netns_get(par->net, par->family);
502-
if (ret < 0)
502+
if (ret < 0) {
503503
pr_info("cannot load conntrack support for proto=%u\n",
504504
par->family);
505+
clusterip_config_entry_put(par->net, config);
506+
clusterip_config_put(config);
507+
return ret;
508+
}
505509

506510
if (!par->net->xt.clusterip_deprecated_warning) {
507511
pr_info("ipt_CLUSTERIP is deprecated and it will removed soon, "
508512
"use xt_cluster instead\n");
509513
par->net->xt.clusterip_deprecated_warning = true;
510514
}
511515

516+
cipinfo->config = config;
512517
return ret;
513518
}
514519

net/ipv4/netfilter/nf_flow_table_ipv4.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static int nf_flow_dnat_ip(const struct flow_offload *flow, struct sk_buff *skb,
111111
default:
112112
return -1;
113113
}
114+
csum_replace4(&iph->check, addr, new_addr);
114115

115116
return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
116117
}

net/ipv6/netfilter.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,19 @@
2121
int ip6_route_me_harder(struct net *net, struct sk_buff *skb)
2222
{
2323
const struct ipv6hdr *iph = ipv6_hdr(skb);
24+
struct sock *sk = sk_to_full_sk(skb->sk);
2425
unsigned int hh_len;
2526
struct dst_entry *dst;
2627
struct flowi6 fl6 = {
27-
.flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
28+
.flowi6_oif = sk ? sk->sk_bound_dev_if : 0,
2829
.flowi6_mark = skb->mark,
29-
.flowi6_uid = sock_net_uid(net, skb->sk),
30+
.flowi6_uid = sock_net_uid(net, sk),
3031
.daddr = iph->daddr,
3132
.saddr = iph->saddr,
3233
};
3334
int err;
3435

35-
dst = ip6_route_output(net, skb->sk, &fl6);
36+
dst = ip6_route_output(net, sk, &fl6);
3637
err = dst->error;
3738
if (err) {
3839
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
@@ -50,7 +51,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb)
5051
if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
5152
xfrm_decode_session(skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) {
5253
skb_dst_set(skb, NULL);
53-
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0);
54+
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
5455
if (IS_ERR(dst))
5556
return PTR_ERR(dst);
5657
skb_dst_set(skb, dst);

net/ipv6/netfilter/ip6t_rpfilter.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,6 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
4848
}
4949

5050
fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
51-
if ((flags & XT_RPFILTER_LOOSE) == 0) {
52-
fl6.flowi6_oif = dev->ifindex;
53-
lookup_flags |= RT6_LOOKUP_F_IFACE;
54-
}
5551

5652
rt = (void *) ip6_route_lookup(net, &fl6, lookup_flags);
5753
if (rt->dst.error)

net/ipv6/netfilter/nf_nat_l3proto_ipv6.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
9999
!l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv6, iphdroff, hdroff,
100100
target, maniptype))
101101
return false;
102+
103+
/* must reload, offset might have changed */
104+
ipv6h = (void *)skb->data + iphdroff;
105+
102106
manip_addr:
103107
if (maniptype == NF_NAT_MANIP_SRC)
104108
ipv6h->saddr = target->src.u3.in6;

net/ipv6/netfilter/nft_fib_ipv6.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
180180
}
181181

182182
*dest = 0;
183-
again:
184183
rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, lookup_flags);
185184
if (rt->dst.error)
186185
goto put_rt_err;
@@ -189,15 +188,8 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
189188
if (rt->rt6i_flags & (RTF_REJECT | RTF_ANYCAST | RTF_LOCAL))
190189
goto put_rt_err;
191190

192-
if (oif && oif != rt->rt6i_idev->dev) {
193-
/* multipath route? Try again with F_IFACE */
194-
if ((lookup_flags & RT6_LOOKUP_F_IFACE) == 0) {
195-
lookup_flags |= RT6_LOOKUP_F_IFACE;
196-
fl6.flowi6_oif = oif->ifindex;
197-
ip6_rt_put(rt);
198-
goto again;
199-
}
200-
}
191+
if (oif && oif != rt->rt6i_idev->dev)
192+
goto put_rt_err;
201193

202194
switch (priv->result) {
203195
case NFT_FIB_RESULT_OIF:

net/netfilter/ipvs/ip_vs_ftp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
260260
buf_len = strlen(buf);
261261

262262
ct = nf_ct_get(skb, &ctinfo);
263-
if (ct && (ct->status & IPS_NAT_MASK)) {
263+
if (ct) {
264264
bool mangled;
265265

266266
/* If mangling fails this function will return 0

net/netfilter/nf_tables_api.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5037,9 +5037,9 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
50375037
{
50385038
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
50395039
const struct nf_flowtable_type *type;
5040+
struct nft_flowtable *flowtable, *ft;
50405041
u8 genmask = nft_genmask_next(net);
50415042
int family = nfmsg->nfgen_family;
5042-
struct nft_flowtable *flowtable;
50435043
struct nft_table *table;
50445044
struct nft_ctx ctx;
50455045
int err, i, k;
@@ -5099,6 +5099,22 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
50995099
goto err3;
51005100

51015101
for (i = 0; i < flowtable->ops_len; i++) {
5102+
if (!flowtable->ops[i].dev)
5103+
continue;
5104+
5105+
list_for_each_entry(ft, &table->flowtables, list) {
5106+
for (k = 0; k < ft->ops_len; k++) {
5107+
if (!ft->ops[k].dev)
5108+
continue;
5109+
5110+
if (flowtable->ops[i].dev == ft->ops[k].dev &&
5111+
flowtable->ops[i].pf == ft->ops[k].pf) {
5112+
err = -EBUSY;
5113+
goto err4;
5114+
}
5115+
}
5116+
}
5117+
51025118
err = nf_register_net_hook(net, &flowtable->ops[i]);
51035119
if (err < 0)
51045120
goto err4;
@@ -5120,7 +5136,7 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
51205136
i = flowtable->ops_len;
51215137
err4:
51225138
for (k = i - 1; k >= 0; k--)
5123-
nf_unregister_net_hook(net, &flowtable->ops[i]);
5139+
nf_unregister_net_hook(net, &flowtable->ops[k]);
51245140

51255141
kfree(flowtable->ops);
51265142
err3:
@@ -5145,6 +5161,11 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk,
51455161
struct nft_table *table;
51465162
struct nft_ctx ctx;
51475163

5164+
if (!nla[NFTA_FLOWTABLE_TABLE] ||
5165+
(!nla[NFTA_FLOWTABLE_NAME] &&
5166+
!nla[NFTA_FLOWTABLE_HANDLE]))
5167+
return -EINVAL;
5168+
51485169
table = nf_tables_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE],
51495170
family, genmask);
51505171
if (IS_ERR(table))

0 commit comments

Comments
 (0)