Skip to content

Commit b3c0a9e

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net 1) Missing proper sanitization for nft_set_desc_concat_parse(). 2) Missing mutex in nf_tables pre_exit path. 3) Possible double hook unregistration from clean_net path. 4) Missing FLOWI_FLAG_ANYSRC flag in flowtable route lookup. Fix incorrect source and destination address in case of NAT. Patch from wenxu. * git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: flowtable: fix nft_flow_route source address for nat case netfilter: flowtable: fix missing FLOWI_FLAG_ANYSRC flag netfilter: nf_tables: double hook unregistration in netns path netfilter: nf_tables: hold mutex on netns pre_exit path netfilter: nf_tables: sanitize nft_set_desc_concat_parse() ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 2e8728c + 97629b2 commit b3c0a9e

File tree

2 files changed

+62
-19
lines changed

2 files changed

+62
-19
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,18 @@ static int nft_netdev_register_hooks(struct net *net,
222222
}
223223

224224
static void nft_netdev_unregister_hooks(struct net *net,
225-
struct list_head *hook_list)
225+
struct list_head *hook_list,
226+
bool release_netdev)
226227
{
227-
struct nft_hook *hook;
228+
struct nft_hook *hook, *next;
228229

229-
list_for_each_entry(hook, hook_list, list)
230+
list_for_each_entry_safe(hook, next, hook_list, list) {
230231
nf_unregister_net_hook(net, &hook->ops);
232+
if (release_netdev) {
233+
list_del(&hook->list);
234+
kfree_rcu(hook, rcu);
235+
}
236+
}
231237
}
232238

233239
static int nf_tables_register_hook(struct net *net,
@@ -253,9 +259,10 @@ static int nf_tables_register_hook(struct net *net,
253259
return nf_register_net_hook(net, &basechain->ops);
254260
}
255261

256-
static void nf_tables_unregister_hook(struct net *net,
257-
const struct nft_table *table,
258-
struct nft_chain *chain)
262+
static void __nf_tables_unregister_hook(struct net *net,
263+
const struct nft_table *table,
264+
struct nft_chain *chain,
265+
bool release_netdev)
259266
{
260267
struct nft_base_chain *basechain;
261268
const struct nf_hook_ops *ops;
@@ -270,11 +277,19 @@ static void nf_tables_unregister_hook(struct net *net,
270277
return basechain->type->ops_unregister(net, ops);
271278

272279
if (nft_base_chain_netdev(table->family, basechain->ops.hooknum))
273-
nft_netdev_unregister_hooks(net, &basechain->hook_list);
280+
nft_netdev_unregister_hooks(net, &basechain->hook_list,
281+
release_netdev);
274282
else
275283
nf_unregister_net_hook(net, &basechain->ops);
276284
}
277285

286+
static void nf_tables_unregister_hook(struct net *net,
287+
const struct nft_table *table,
288+
struct nft_chain *chain)
289+
{
290+
return __nf_tables_unregister_hook(net, table, chain, false);
291+
}
292+
278293
static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans)
279294
{
280295
struct nftables_pernet *nft_net = nft_pernet(net);
@@ -4246,6 +4261,9 @@ static int nft_set_desc_concat_parse(const struct nlattr *attr,
42464261
u32 len;
42474262
int err;
42484263

4264+
if (desc->field_count >= ARRAY_SIZE(desc->field_len))
4265+
return -E2BIG;
4266+
42494267
err = nla_parse_nested_deprecated(tb, NFTA_SET_FIELD_MAX, attr,
42504268
nft_concat_policy, NULL);
42514269
if (err < 0)
@@ -4255,9 +4273,8 @@ static int nft_set_desc_concat_parse(const struct nlattr *attr,
42554273
return -EINVAL;
42564274

42574275
len = ntohl(nla_get_be32(tb[NFTA_SET_FIELD_LEN]));
4258-
4259-
if (len * BITS_PER_BYTE / 32 > NFT_REG32_COUNT)
4260-
return -E2BIG;
4276+
if (!len || len > U8_MAX)
4277+
return -EINVAL;
42614278

42624279
desc->field_len[desc->field_count++] = len;
42634280

@@ -4268,7 +4285,8 @@ static int nft_set_desc_concat(struct nft_set_desc *desc,
42684285
const struct nlattr *nla)
42694286
{
42704287
struct nlattr *attr;
4271-
int rem, err;
4288+
u32 num_regs = 0;
4289+
int rem, err, i;
42724290

42734291
nla_for_each_nested(attr, nla, rem) {
42744292
if (nla_type(attr) != NFTA_LIST_ELEM)
@@ -4279,6 +4297,12 @@ static int nft_set_desc_concat(struct nft_set_desc *desc,
42794297
return err;
42804298
}
42814299

4300+
for (i = 0; i < desc->field_count; i++)
4301+
num_regs += DIV_ROUND_UP(desc->field_len[i], sizeof(u32));
4302+
4303+
if (num_regs > NFT_REG32_COUNT)
4304+
return -E2BIG;
4305+
42824306
return 0;
42834307
}
42844308

@@ -7298,13 +7322,25 @@ static void nft_unregister_flowtable_hook(struct net *net,
72987322
FLOW_BLOCK_UNBIND);
72997323
}
73007324

7301-
static void nft_unregister_flowtable_net_hooks(struct net *net,
7302-
struct list_head *hook_list)
7325+
static void __nft_unregister_flowtable_net_hooks(struct net *net,
7326+
struct list_head *hook_list,
7327+
bool release_netdev)
73037328
{
7304-
struct nft_hook *hook;
7329+
struct nft_hook *hook, *next;
73057330

7306-
list_for_each_entry(hook, hook_list, list)
7331+
list_for_each_entry_safe(hook, next, hook_list, list) {
73077332
nf_unregister_net_hook(net, &hook->ops);
7333+
if (release_netdev) {
7334+
list_del(&hook->list);
7335+
kfree_rcu(hook);
7336+
}
7337+
}
7338+
}
7339+
7340+
static void nft_unregister_flowtable_net_hooks(struct net *net,
7341+
struct list_head *hook_list)
7342+
{
7343+
__nft_unregister_flowtable_net_hooks(net, hook_list, false);
73087344
}
73097345

73107346
static int nft_register_flowtable_net_hooks(struct net *net,
@@ -9746,9 +9782,10 @@ static void __nft_release_hook(struct net *net, struct nft_table *table)
97469782
struct nft_chain *chain;
97479783

97489784
list_for_each_entry(chain, &table->chains, list)
9749-
nf_tables_unregister_hook(net, table, chain);
9785+
__nf_tables_unregister_hook(net, table, chain, true);
97509786
list_for_each_entry(flowtable, &table->flowtables, list)
9751-
nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list);
9787+
__nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list,
9788+
true);
97529789
}
97539790

97549791
static void __nft_release_hooks(struct net *net)
@@ -9887,7 +9924,11 @@ static int __net_init nf_tables_init_net(struct net *net)
98879924

98889925
static void __net_exit nf_tables_pre_exit_net(struct net *net)
98899926
{
9927+
struct nftables_pernet *nft_net = nft_pernet(net);
9928+
9929+
mutex_lock(&nft_net->commit_mutex);
98909930
__nft_release_hooks(net);
9931+
mutex_unlock(&nft_net->commit_mutex);
98919932
}
98929933

98939934
static void __net_exit nf_tables_exit_net(struct net *net)

net/netfilter/nft_flow_offload.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,19 +232,21 @@ static int nft_flow_route(const struct nft_pktinfo *pkt,
232232
switch (nft_pf(pkt)) {
233233
case NFPROTO_IPV4:
234234
fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
235-
fl.u.ip4.saddr = ct->tuplehash[dir].tuple.dst.u3.ip;
235+
fl.u.ip4.saddr = ct->tuplehash[!dir].tuple.src.u3.ip;
236236
fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex;
237237
fl.u.ip4.flowi4_iif = this_dst->dev->ifindex;
238238
fl.u.ip4.flowi4_tos = RT_TOS(ip_hdr(pkt->skb)->tos);
239239
fl.u.ip4.flowi4_mark = pkt->skb->mark;
240+
fl.u.ip4.flowi4_flags = FLOWI_FLAG_ANYSRC;
240241
break;
241242
case NFPROTO_IPV6:
242243
fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
243-
fl.u.ip6.saddr = ct->tuplehash[dir].tuple.dst.u3.in6;
244+
fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.src.u3.in6;
244245
fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex;
245246
fl.u.ip6.flowi6_iif = this_dst->dev->ifindex;
246247
fl.u.ip6.flowlabel = ip6_flowinfo(ipv6_hdr(pkt->skb));
247248
fl.u.ip6.flowi6_mark = pkt->skb->mark;
249+
fl.u.ip6.flowi6_flags = FLOWI_FLAG_ANYSRC;
248250
break;
249251
}
250252

0 commit comments

Comments
 (0)