Skip to content

Commit

Permalink
Merge tag 'nf-24-02-22' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…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/[email protected]
Signed-off-by: Paolo Abeni <[email protected]>
  • Loading branch information
Paolo Abeni committed Feb 22, 2024
2 parents fdcd446 + 195e5f8 commit 9ff2794
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 43 deletions.
2 changes: 1 addition & 1 deletion include/net/netfilter/nf_flow_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
17 changes: 14 additions & 3 deletions net/netfilter/nf_flow_table_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand All @@ -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);
Expand Down
81 changes: 42 additions & 39 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2503,37 +2505,38 @@ 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;
if (nft_is_base_chain(chain))
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);

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 9ff2794

Please sign in to comment.