Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Browse files Browse the repository at this point in the history
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/20220531215839.84765-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
kuba-moo committed Jun 1, 2022
2 parents 2e8728c + 97629b2 commit b3c0a9e
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 19 deletions.
75 changes: 58 additions & 17 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,18 @@ static int nft_netdev_register_hooks(struct net *net,
}

static void nft_netdev_unregister_hooks(struct net *net,
struct list_head *hook_list)
struct list_head *hook_list,
bool release_netdev)
{
struct nft_hook *hook;
struct nft_hook *hook, *next;

list_for_each_entry(hook, hook_list, list)
list_for_each_entry_safe(hook, next, hook_list, list) {
nf_unregister_net_hook(net, &hook->ops);
if (release_netdev) {
list_del(&hook->list);
kfree_rcu(hook, rcu);
}
}
}

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

static void nf_tables_unregister_hook(struct net *net,
const struct nft_table *table,
struct nft_chain *chain)
static void __nf_tables_unregister_hook(struct net *net,
const struct nft_table *table,
struct nft_chain *chain,
bool release_netdev)
{
struct nft_base_chain *basechain;
const struct nf_hook_ops *ops;
Expand All @@ -270,11 +277,19 @@ static void nf_tables_unregister_hook(struct net *net,
return basechain->type->ops_unregister(net, ops);

if (nft_base_chain_netdev(table->family, basechain->ops.hooknum))
nft_netdev_unregister_hooks(net, &basechain->hook_list);
nft_netdev_unregister_hooks(net, &basechain->hook_list,
release_netdev);
else
nf_unregister_net_hook(net, &basechain->ops);
}

static void nf_tables_unregister_hook(struct net *net,
const struct nft_table *table,
struct nft_chain *chain)
{
return __nf_tables_unregister_hook(net, table, chain, false);
}

static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans)
{
struct nftables_pernet *nft_net = nft_pernet(net);
Expand Down Expand Up @@ -4246,6 +4261,9 @@ static int nft_set_desc_concat_parse(const struct nlattr *attr,
u32 len;
int err;

if (desc->field_count >= ARRAY_SIZE(desc->field_len))
return -E2BIG;

err = nla_parse_nested_deprecated(tb, NFTA_SET_FIELD_MAX, attr,
nft_concat_policy, NULL);
if (err < 0)
Expand All @@ -4255,9 +4273,8 @@ static int nft_set_desc_concat_parse(const struct nlattr *attr,
return -EINVAL;

len = ntohl(nla_get_be32(tb[NFTA_SET_FIELD_LEN]));

if (len * BITS_PER_BYTE / 32 > NFT_REG32_COUNT)
return -E2BIG;
if (!len || len > U8_MAX)
return -EINVAL;

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

Expand All @@ -4268,7 +4285,8 @@ static int nft_set_desc_concat(struct nft_set_desc *desc,
const struct nlattr *nla)
{
struct nlattr *attr;
int rem, err;
u32 num_regs = 0;
int rem, err, i;

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

for (i = 0; i < desc->field_count; i++)
num_regs += DIV_ROUND_UP(desc->field_len[i], sizeof(u32));

if (num_regs > NFT_REG32_COUNT)
return -E2BIG;

return 0;
}

Expand Down Expand Up @@ -7298,13 +7322,25 @@ static void nft_unregister_flowtable_hook(struct net *net,
FLOW_BLOCK_UNBIND);
}

static void nft_unregister_flowtable_net_hooks(struct net *net,
struct list_head *hook_list)
static void __nft_unregister_flowtable_net_hooks(struct net *net,
struct list_head *hook_list,
bool release_netdev)
{
struct nft_hook *hook;
struct nft_hook *hook, *next;

list_for_each_entry(hook, hook_list, list)
list_for_each_entry_safe(hook, next, hook_list, list) {
nf_unregister_net_hook(net, &hook->ops);
if (release_netdev) {
list_del(&hook->list);
kfree_rcu(hook);
}
}
}

static void nft_unregister_flowtable_net_hooks(struct net *net,
struct list_head *hook_list)
{
__nft_unregister_flowtable_net_hooks(net, hook_list, false);
}

static int nft_register_flowtable_net_hooks(struct net *net,
Expand Down Expand Up @@ -9746,9 +9782,10 @@ static void __nft_release_hook(struct net *net, struct nft_table *table)
struct nft_chain *chain;

list_for_each_entry(chain, &table->chains, list)
nf_tables_unregister_hook(net, table, chain);
__nf_tables_unregister_hook(net, table, chain, true);
list_for_each_entry(flowtable, &table->flowtables, list)
nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list);
__nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list,
true);
}

static void __nft_release_hooks(struct net *net)
Expand Down Expand Up @@ -9887,7 +9924,11 @@ static int __net_init nf_tables_init_net(struct net *net)

static void __net_exit nf_tables_pre_exit_net(struct net *net)
{
struct nftables_pernet *nft_net = nft_pernet(net);

mutex_lock(&nft_net->commit_mutex);
__nft_release_hooks(net);
mutex_unlock(&nft_net->commit_mutex);
}

static void __net_exit nf_tables_exit_net(struct net *net)
Expand Down
6 changes: 4 additions & 2 deletions net/netfilter/nft_flow_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,19 +232,21 @@ static int nft_flow_route(const struct nft_pktinfo *pkt,
switch (nft_pf(pkt)) {
case NFPROTO_IPV4:
fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
fl.u.ip4.saddr = ct->tuplehash[dir].tuple.dst.u3.ip;
fl.u.ip4.saddr = ct->tuplehash[!dir].tuple.src.u3.ip;
fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex;
fl.u.ip4.flowi4_iif = this_dst->dev->ifindex;
fl.u.ip4.flowi4_tos = RT_TOS(ip_hdr(pkt->skb)->tos);
fl.u.ip4.flowi4_mark = pkt->skb->mark;
fl.u.ip4.flowi4_flags = FLOWI_FLAG_ANYSRC;
break;
case NFPROTO_IPV6:
fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
fl.u.ip6.saddr = ct->tuplehash[dir].tuple.dst.u3.in6;
fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.src.u3.in6;
fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex;
fl.u.ip6.flowi6_iif = this_dst->dev->ifindex;
fl.u.ip6.flowlabel = ip6_flowinfo(ipv6_hdr(pkt->skb));
fl.u.ip6.flowi6_mark = pkt->skb->mark;
fl.u.ip6.flowi6_flags = FLOWI_FLAG_ANYSRC;
break;
}

Expand Down

0 comments on commit b3c0a9e

Please sign in to comment.