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/20220531215839.84765-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
b3c0a9efbe
|
@ -222,12 +222,18 @@ err_register:
|
|||
}
|
||||
|
||||
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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
bool release_netdev)
|
||||
{
|
||||
struct nft_hook *hook, *next;
|
||||
|
||||
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)
|
||||
{
|
||||
struct nft_hook *hook;
|
||||
|
||||
list_for_each_entry(hook, hook_list, list)
|
||||
nf_unregister_net_hook(net, &hook->ops);
|
||||
__nft_unregister_flowtable_net_hooks(net, hook_list, false);
|
||||
}
|
||||
|
||||
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)
|
|||
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)
|
||||
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue