1

netfilter pull request 24-02-22

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEN9lkrMBJgcdVAPub1V2XiooUIOQFAmXWjUEACgkQ1V2XiooU
 IOQEqA//c15K4sL5v3ROUgDKYo7d5W7mnb3c9T2b2I4tZIyAj+f1+6DhGz2PB/5L
 BjdAXbz2FrrkSt/x4fcu0CkcXC2d5tVcVhvt+CTpaph70xOXBL0XtN+x3NfXlZVg
 r9Q/6tV3pBE6u6LdqogQsQtehhqYMgzPVfKuUVYbvM4efqV/vvKiBbHl5DedtKk0
 GKiwGEKnXbBUxpJueSUAX/+C64Ldlhw4MVswkJfjA8r56FJEsxPet9tlAphqd+6P
 qg1bECQf3NQw8DVBtMc9U1Izb8HhiGEskG72e450Uo1X7SL6EACDFCMVTAeEz+fu
 sDNPpS/V7PEP3tImJm0Rj6N6iYGL19tWfCVMdesP+KF5yokNbQF54Xgz4ETkVyrt
 EZkR5JL6pRLBQ7FJ/2TD0IIFEn09KayMXLI0Dlugl90lOsn1T6Dnmmh8563nZ2eT
 6zio/4NqYRzCXSieCs3zHRZCH0l2tttkkKi0MhVJwGBJd8Wl0qeXHK/UxlE5Pfkn
 qhD2ryuCHbIad2JxS8mb1pIzMhw8sy3LsxQQ91CShQ2ujTLY35dhcWJPDm8u77md
 VE4lTUmj8uvExLjG/xf+5bzvTutYUGdacRmYwzyFTl/ix3tYvg75GoI4l2iGd4xl
 6COxPtLaFDkxo5GxODLrmjxe11E8nT2BKI7rPsOjee8ueAzJZdM=
 =iPIR
 -----END PGP SIGNATURE-----

Merge tag 'nf-24-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Pablo Neira Ayuso says:

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

The following patchset contains Netfilter fixes for net:

1) If user requests to wake up a table and hook fails, restore the
   dormant flag from the error path, from Florian Westphal.

2) Reset dst after transferring it to the flow object, otherwise dst
   gets released twice from the error path.

3) Release dst in case the flowtable selects a direct xmit path, eg.
   transmission to bridge port. Otherwise, dst is memleaked.

4) Register basechain and flowtable hooks at the end of the command.
   Error path releases these datastructure without waiting for the
   rcu grace period.

5) Use kzalloc() to initialize struct nft_hook to fix a KMSAN report
   on access to hook type, also from Florian Westphal.

netfilter pull request 24-02-22

* tag 'nf-24-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: nf_tables: use kzalloc for hook allocation
  netfilter: nf_tables: register hooks last when adding new chain/flowtable
  netfilter: nft_flow_offload: release dst in case direct xmit path is used
  netfilter: nft_flow_offload: reset dst in route object after setting up flow
  netfilter: nf_tables: set dormant flag on hook register failure
====================

Link: https://lore.kernel.org/r/20240222000843.146665-1-pablo@netfilter.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2024-02-22 10:20:50 +01:00
commit 9ff2794306
3 changed files with 57 additions and 43 deletions

View File

@ -276,7 +276,7 @@ nf_flow_table_offload_del_cb(struct nf_flowtable *flow_table,
}
void flow_offload_route_init(struct flow_offload *flow,
const struct nf_flow_route *route);
struct nf_flow_route *route);
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
void flow_offload_refresh(struct nf_flowtable *flow_table,

View File

@ -87,12 +87,22 @@ static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple)
return 0;
}
static struct dst_entry *nft_route_dst_fetch(struct nf_flow_route *route,
enum flow_offload_tuple_dir dir)
{
struct dst_entry *dst = route->tuple[dir].dst;
route->tuple[dir].dst = NULL;
return dst;
}
static int flow_offload_fill_route(struct flow_offload *flow,
const struct nf_flow_route *route,
struct nf_flow_route *route,
enum flow_offload_tuple_dir dir)
{
struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
struct dst_entry *dst = route->tuple[dir].dst;
struct dst_entry *dst = nft_route_dst_fetch(route, dir);
int i, j = 0;
switch (flow_tuple->l3proto) {
@ -122,6 +132,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
ETH_ALEN);
flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
flow_tuple->out.hw_ifidx = route->tuple[dir].out.hw_ifindex;
dst_release(dst);
break;
case FLOW_OFFLOAD_XMIT_XFRM:
case FLOW_OFFLOAD_XMIT_NEIGH:
@ -146,7 +157,7 @@ static void nft_flow_dst_release(struct flow_offload *flow,
}
void flow_offload_route_init(struct flow_offload *flow,
const struct nf_flow_route *route)
struct nf_flow_route *route)
{
flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL);
flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY);

View File

@ -684,15 +684,16 @@ static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj)
return err;
}
static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
struct nft_flowtable *flowtable)
static struct nft_trans *
nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
struct nft_flowtable *flowtable)
{
struct nft_trans *trans;
trans = nft_trans_alloc(ctx, msg_type,
sizeof(struct nft_trans_flowtable));
if (trans == NULL)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
if (msg_type == NFT_MSG_NEWFLOWTABLE)
nft_activate_next(ctx->net, flowtable);
@ -701,22 +702,22 @@ static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
nft_trans_flowtable(trans) = flowtable;
nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
return trans;
}
static int nft_delflowtable(struct nft_ctx *ctx,
struct nft_flowtable *flowtable)
{
int err;
struct nft_trans *trans;
err = nft_trans_flowtable_add(ctx, NFT_MSG_DELFLOWTABLE, flowtable);
if (err < 0)
return err;
trans = nft_trans_flowtable_add(ctx, NFT_MSG_DELFLOWTABLE, flowtable);
if (IS_ERR(trans))
return PTR_ERR(trans);
nft_deactivate_next(ctx->net, flowtable);
nft_use_dec(&ctx->table->use);
return err;
return 0;
}
static void __nft_reg_track_clobber(struct nft_regs_track *track, u8 dreg)
@ -1251,6 +1252,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
return 0;
err_register_hooks:
ctx->table->flags |= NFT_TABLE_F_DORMANT;
nft_trans_destroy(trans);
return ret;
}
@ -2080,7 +2082,7 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
struct nft_hook *hook;
int err;
hook = kmalloc(sizeof(struct nft_hook), GFP_KERNEL_ACCOUNT);
hook = kzalloc(sizeof(struct nft_hook), GFP_KERNEL_ACCOUNT);
if (!hook) {
err = -ENOMEM;
goto err_hook_alloc;
@ -2503,19 +2505,15 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
RCU_INIT_POINTER(chain->blob_gen_0, blob);
RCU_INIT_POINTER(chain->blob_gen_1, blob);
err = nf_tables_register_hook(net, table, chain);
if (err < 0)
goto err_destroy_chain;
if (!nft_use_inc(&table->use)) {
err = -EMFILE;
goto err_use;
goto err_destroy_chain;
}
trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
goto err_unregister_hook;
goto err_trans;
}
nft_trans_chain_policy(trans) = NFT_CHAIN_POLICY_UNSET;
@ -2523,17 +2521,22 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
nft_trans_chain_policy(trans) = policy;
err = nft_chain_add(table, chain);
if (err < 0) {
nft_trans_destroy(trans);
goto err_unregister_hook;
}
if (err < 0)
goto err_chain_add;
/* This must be LAST to ensure no packets are walking over this chain. */
err = nf_tables_register_hook(net, table, chain);
if (err < 0)
goto err_register_hook;
return 0;
err_unregister_hook:
err_register_hook:
nft_chain_del(chain);
err_chain_add:
nft_trans_destroy(trans);
err_trans:
nft_use_dec_restore(&table->use);
err_use:
nf_tables_unregister_hook(net, table, chain);
err_destroy_chain:
nf_tables_chain_destroy(ctx);
@ -8455,9 +8458,9 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
u8 family = info->nfmsg->nfgen_family;
const struct nf_flowtable_type *type;
struct nft_flowtable *flowtable;
struct nft_hook *hook, *next;
struct net *net = info->net;
struct nft_table *table;
struct nft_trans *trans;
struct nft_ctx ctx;
int err;
@ -8537,34 +8540,34 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
err = nft_flowtable_parse_hook(&ctx, nla, &flowtable_hook, flowtable,
extack, true);
if (err < 0)
goto err4;
goto err_flowtable_parse_hooks;
list_splice(&flowtable_hook.list, &flowtable->hook_list);
flowtable->data.priority = flowtable_hook.priority;
flowtable->hooknum = flowtable_hook.num;
trans = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
goto err_flowtable_trans;
}
/* This must be LAST to ensure no packets are walking over this flowtable. */
err = nft_register_flowtable_net_hooks(ctx.net, table,
&flowtable->hook_list,
flowtable);
if (err < 0) {
nft_hooks_destroy(&flowtable->hook_list);
goto err4;
}
err = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
if (err < 0)
goto err5;
goto err_flowtable_hooks;
list_add_tail_rcu(&flowtable->list, &table->flowtables);
return 0;
err5:
list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
nft_unregister_flowtable_hook(net, flowtable, hook);
list_del_rcu(&hook->list);
kfree_rcu(hook, rcu);
}
err4:
err_flowtable_hooks:
nft_trans_destroy(trans);
err_flowtable_trans:
nft_hooks_destroy(&flowtable->hook_list);
err_flowtable_parse_hooks:
flowtable->data.type->free(&flowtable->data);
err3:
module_put(type->owner);