netfilter pull request 26-09-11

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEjF9xRqF1emXiQiqU1w0aZmrPKyEFAmqj4z4ACgkQ1w0aZmrP
 KyFvYw//RFZnFWU4PPLMWFiHCKfBQXaDwCM6ADS2phgVLTLbs0OEQ8Mw+XvkOt2v
 ardyCu5Ujy7udvF2kaha0ACNw+Z3DYOVu+VkzhKJ4TrBaKhr9kob6Vuczdw3QQ10
 Kx6UAh3PYWV2BHqB+IoNzd40PBVTHs2ckeSntUNJ1nkGQb2f+kkjWLj3tY+OwaUv
 fUlD2e34GXdQDEAvYaRHn7Lkv+PMXx4r40EQ238yH9+wTtqBIgCRogTbLHQ3d1Lu
 r9RHMqHBOkJu5C+gDcVD1r7TXf6S1wBcohEGSvNO+VwF5KDHNylQYS/ONrnUgvRL
 9Mr9GmYXgwLN9FxNjYxlo7cjipXHvpONMJ4B0+iz1VE0SL0Z4BNqfpBISqsWW9xP
 Ox3l4IjnV0Ver+tBcNml6JcwGip1cggHrIi9lb1Zf4cMk+ndq3O+sSSW+EFpKpDn
 szu9mUrAaHpVOEHUeFqTYjC/Xvq1x1W7QkZ5BqNo4jycROhnRWeWvvUSebW1ruL+
 exWYMVA0w3aXPN6tfjGlHMCUuCgMLpOkSvXBgPKIILqnH7rueT5Qhh6wDqpD9NkW
 xaY1J56MEuhzn2Cf8YkVDdtSgXHc9dteRmg/dLLhnubycewEjDYZTm0vGnLDBYVb
 0xvVzNBQm8e7oEoczZQI9Z8Q83Pqi+OhVopZRc7SRaqJCH3pAUU=
 =H3Kp
 -----END PGP SIGNATURE-----

Merge tag 'nf-26-09-11' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

1) Fix KMSAN reports an uninit-value in nf_nat_setup_info() for netmap,
   from Theodor Arsenij Larionov Trichkine.

2) Restrict deletion of netdevice in basechain and flowtable to exact
   matching only, from Fernando F. Mancera.

3) Fix nf_nat_register_fn() error path allowing for a memleak.

4) Hold reference on ct until flow is released to address, otherwise
   access to release ct->ext or different ct due to typesafe RCU
   semantics.

* tag 'nf-26-09-11' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: flowtable: hold reference on ct until flow is released
  netfilter: nf_nat: unregister and release hooks on error
  netfilter: nf_tables: fix device name and prefix match in hook lookup
  netfilter: nft_nat: fully initialise new_addr in netmap setup
====================

Link: https://patch.msgid.link/20260913205447.1889203-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-09-14 17:06:52 -07:00
commit 6c21ebc813
4 changed files with 54 additions and 28 deletions

View File

@ -258,6 +258,14 @@ static void flow_offload_route_release(struct flow_offload *flow)
nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_REPLY);
}
static void flow_offload_free_rcu(struct rcu_head *rcu_head)
{
struct flow_offload *flow = container_of(rcu_head, struct flow_offload, rcu_head);
nf_ct_put(flow->ct);
kfree(flow);
}
void flow_offload_free(struct flow_offload *flow)
{
switch (flow->type) {
@ -267,8 +275,7 @@ void flow_offload_free(struct flow_offload *flow)
default:
break;
}
nf_ct_put(flow->ct);
kfree_rcu(flow, rcu_head);
call_rcu(&flow->rcu_head, flow_offload_free_rcu);
}
EXPORT_SYMBOL_GPL(flow_offload_free);
@ -854,6 +861,7 @@ static int __init nf_flow_table_module_init(void)
static void __exit nf_flow_table_module_exit(void)
{
rcu_barrier();
nf_flow_table_offload_exit();
unregister_pernet_subsys(&nf_flow_table_net_ops);
kmem_cache_destroy(flow_offload_cachep);

View File

@ -1224,31 +1224,45 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
}
ret = nf_register_net_hooks(net, nat_ops, ops_count);
if (ret < 0) {
mutex_unlock(&nf_nat_proto_mutex);
for (i = 0; i < ops_count; i++) {
priv = nat_ops[i].priv;
kfree_rcu(priv, rcu_head);
}
kfree_rcu(nat_ops, rcu);
return ret;
}
nat_proto_net->nat_hook_ops = nat_ops;
if (ret < 0)
goto err_free_hooks;
} else {
nat_ops = nat_proto_net->nat_hook_ops;
}
nat_ops = nat_proto_net->nat_hook_ops;
priv = nat_ops[hooknum].priv;
if (WARN_ON_ONCE(!priv)) {
mutex_unlock(&nf_nat_proto_mutex);
return -EOPNOTSUPP;
ret = -EOPNOTSUPP;
goto err_unregister_hooks;
}
ret = nf_hook_entries_insert_raw(&priv->entries, ops);
if (ret == 0)
nat_proto_net->users++;
if (ret)
goto err_unregister_hooks;
if (!nat_proto_net->nat_hook_ops)
nat_proto_net->nat_hook_ops = nat_ops;
nat_proto_net->users++;
mutex_unlock(&nf_nat_proto_mutex);
return 0;
err_unregister_hooks:
if (nat_proto_net->nat_hook_ops) {
mutex_unlock(&nf_nat_proto_mutex);
return ret;
}
nf_unregister_net_hooks(net, nat_ops, ops_count);
err_free_hooks:
mutex_unlock(&nf_nat_proto_mutex);
for (i = 0; i < ops_count; i++) {
priv = nat_ops[i].priv;
kfree_rcu(priv, rcu_head);
}
kfree_rcu(nat_ops, rcu);
return ret;
}

View File

@ -2440,11 +2440,14 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
}
static struct nft_hook *nft_hook_list_find(struct list_head *hook_list,
const struct nft_hook *this)
const struct nft_hook *this,
bool strict)
{
struct nft_hook *hook;
list_for_each_entry(hook, hook_list, list) {
if (strict && hook->ifnamelen != this->ifnamelen)
continue;
if (!strncmp(hook->ifname, this->ifname,
min(hook->ifnamelen, this->ifnamelen))) {
if (hook->flags & NFT_HOOK_REMOVE)
@ -2486,7 +2489,7 @@ static int nf_tables_parse_netdev_hooks(struct net *net,
err = PTR_ERR(hook);
goto err_hook;
}
if (nft_hook_list_find(hook_list, hook)) {
if (nft_hook_list_find(hook_list, hook, false)) {
NL_SET_BAD_ATTR(extack, tmp);
nft_netdev_hook_free(hook);
err = -EEXIST;
@ -2943,7 +2946,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
ops->hook = basechain->ops.hook;
}
if (nft_hook_list_find(&basechain->hook_list, h)) {
if (nft_hook_list_find(&basechain->hook_list, h, false)) {
list_del(&h->list);
nft_netdev_hook_free(h);
continue;
@ -2956,7 +2959,8 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
!nft_trans_chain_update(trans))
continue;
if (nft_hook_list_find(&nft_trans_chain_hooks(trans), h)) {
if (nft_hook_list_find(&nft_trans_chain_hooks(trans),
h, false)) {
nft_chain_release_hook(&hook);
return -EEXIST;
}
@ -3257,7 +3261,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
return err;
list_for_each_entry(this, &chain_hook.list, list) {
hook = nft_hook_list_find(&basechain->hook_list, this);
hook = nft_hook_list_find(&basechain->hook_list, this, true);
if (!hook) {
err = -ENOENT;
goto err_chain_del_hook;
@ -9053,7 +9057,7 @@ static int nft_register_flowtable_net_hooks(struct net *net,
if (!nft_is_active_next(net, ft))
continue;
if (nft_hook_list_find(&ft->hook_list, hook)) {
if (nft_hook_list_find(&ft->hook_list, hook, false)) {
err = -EEXIST;
goto err_unregister_net_hooks;
}
@ -9130,7 +9134,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
return err;
list_for_each_entry_safe(hook, next, &flowtable_hook.list, list) {
if (nft_hook_list_find(&flowtable->hook_list, hook)) {
if (nft_hook_list_find(&flowtable->hook_list, hook, false)) {
list_del(&hook->list);
nft_netdev_hook_free(hook);
continue;
@ -9143,7 +9147,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
!nft_trans_flowtable_update(trans))
continue;
if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook)) {
if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook, false)) {
err = -EEXIST;
goto err_flowtable_update_hook;
}
@ -9363,7 +9367,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx,
return err;
list_for_each_entry(this, &flowtable_hook.list, list) {
hook = nft_hook_list_find(&flowtable->hook_list, this);
hook = nft_hook_list_find(&flowtable->hook_list, this, true);
if (!hook) {
err = -ENOENT;
goto err_flowtable_del_hook;

View File

@ -64,8 +64,8 @@ static void nft_nat_setup_netmap(struct nf_nat_range2 *range,
const struct nft_pktinfo *pkt,
const struct nft_nat *priv)
{
union nf_inet_addr new_addr = {};
struct sk_buff *skb = pkt->skb;
union nf_inet_addr new_addr;
__be32 netmask;
int i, len = 0;