Skip to content

Commit 9ff2794

Browse files
author
Paolo Abeni
committed
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/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents fdcd446 + 195e5f8 commit 9ff2794

File tree

3 files changed

+57
-43
lines changed

3 files changed

+57
-43
lines changed

include/net/netfilter/nf_flow_table.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ nf_flow_table_offload_del_cb(struct nf_flowtable *flow_table,
276276
}
277277

278278
void flow_offload_route_init(struct flow_offload *flow,
279-
const struct nf_flow_route *route);
279+
struct nf_flow_route *route);
280280

281281
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
282282
void flow_offload_refresh(struct nf_flowtable *flow_table,

net/netfilter/nf_flow_table_core.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,22 @@ static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple)
8787
return 0;
8888
}
8989

90+
static struct dst_entry *nft_route_dst_fetch(struct nf_flow_route *route,
91+
enum flow_offload_tuple_dir dir)
92+
{
93+
struct dst_entry *dst = route->tuple[dir].dst;
94+
95+
route->tuple[dir].dst = NULL;
96+
97+
return dst;
98+
}
99+
90100
static int flow_offload_fill_route(struct flow_offload *flow,
91-
const struct nf_flow_route *route,
101+
struct nf_flow_route *route,
92102
enum flow_offload_tuple_dir dir)
93103
{
94104
struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
95-
struct dst_entry *dst = route->tuple[dir].dst;
105+
struct dst_entry *dst = nft_route_dst_fetch(route, dir);
96106
int i, j = 0;
97107

98108
switch (flow_tuple->l3proto) {
@@ -122,6 +132,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
122132
ETH_ALEN);
123133
flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
124134
flow_tuple->out.hw_ifidx = route->tuple[dir].out.hw_ifindex;
135+
dst_release(dst);
125136
break;
126137
case FLOW_OFFLOAD_XMIT_XFRM:
127138
case FLOW_OFFLOAD_XMIT_NEIGH:
@@ -146,7 +157,7 @@ static void nft_flow_dst_release(struct flow_offload *flow,
146157
}
147158

148159
void flow_offload_route_init(struct flow_offload *flow,
149-
const struct nf_flow_route *route)
160+
struct nf_flow_route *route)
150161
{
151162
flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL);
152163
flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY);

net/netfilter/nf_tables_api.c

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -684,15 +684,16 @@ static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj)
684684
return err;
685685
}
686686

687-
static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
688-
struct nft_flowtable *flowtable)
687+
static struct nft_trans *
688+
nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
689+
struct nft_flowtable *flowtable)
689690
{
690691
struct nft_trans *trans;
691692

692693
trans = nft_trans_alloc(ctx, msg_type,
693694
sizeof(struct nft_trans_flowtable));
694695
if (trans == NULL)
695-
return -ENOMEM;
696+
return ERR_PTR(-ENOMEM);
696697

697698
if (msg_type == NFT_MSG_NEWFLOWTABLE)
698699
nft_activate_next(ctx->net, flowtable);
@@ -701,22 +702,22 @@ static int nft_trans_flowtable_add(struct nft_ctx *ctx, int msg_type,
701702
nft_trans_flowtable(trans) = flowtable;
702703
nft_trans_commit_list_add_tail(ctx->net, trans);
703704

704-
return 0;
705+
return trans;
705706
}
706707

707708
static int nft_delflowtable(struct nft_ctx *ctx,
708709
struct nft_flowtable *flowtable)
709710
{
710-
int err;
711+
struct nft_trans *trans;
711712

712-
err = nft_trans_flowtable_add(ctx, NFT_MSG_DELFLOWTABLE, flowtable);
713-
if (err < 0)
714-
return err;
713+
trans = nft_trans_flowtable_add(ctx, NFT_MSG_DELFLOWTABLE, flowtable);
714+
if (IS_ERR(trans))
715+
return PTR_ERR(trans);
715716

716717
nft_deactivate_next(ctx->net, flowtable);
717718
nft_use_dec(&ctx->table->use);
718719

719-
return err;
720+
return 0;
720721
}
721722

722723
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)
12511252
return 0;
12521253

12531254
err_register_hooks:
1255+
ctx->table->flags |= NFT_TABLE_F_DORMANT;
12541256
nft_trans_destroy(trans);
12551257
return ret;
12561258
}
@@ -2080,7 +2082,7 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
20802082
struct nft_hook *hook;
20812083
int err;
20822084

2083-
hook = kmalloc(sizeof(struct nft_hook), GFP_KERNEL_ACCOUNT);
2085+
hook = kzalloc(sizeof(struct nft_hook), GFP_KERNEL_ACCOUNT);
20842086
if (!hook) {
20852087
err = -ENOMEM;
20862088
goto err_hook_alloc;
@@ -2503,37 +2505,38 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
25032505
RCU_INIT_POINTER(chain->blob_gen_0, blob);
25042506
RCU_INIT_POINTER(chain->blob_gen_1, blob);
25052507

2506-
err = nf_tables_register_hook(net, table, chain);
2507-
if (err < 0)
2508-
goto err_destroy_chain;
2509-
25102508
if (!nft_use_inc(&table->use)) {
25112509
err = -EMFILE;
2512-
goto err_use;
2510+
goto err_destroy_chain;
25132511
}
25142512

25152513
trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN);
25162514
if (IS_ERR(trans)) {
25172515
err = PTR_ERR(trans);
2518-
goto err_unregister_hook;
2516+
goto err_trans;
25192517
}
25202518

25212519
nft_trans_chain_policy(trans) = NFT_CHAIN_POLICY_UNSET;
25222520
if (nft_is_base_chain(chain))
25232521
nft_trans_chain_policy(trans) = policy;
25242522

25252523
err = nft_chain_add(table, chain);
2526-
if (err < 0) {
2527-
nft_trans_destroy(trans);
2528-
goto err_unregister_hook;
2529-
}
2524+
if (err < 0)
2525+
goto err_chain_add;
2526+
2527+
/* This must be LAST to ensure no packets are walking over this chain. */
2528+
err = nf_tables_register_hook(net, table, chain);
2529+
if (err < 0)
2530+
goto err_register_hook;
25302531

25312532
return 0;
25322533

2533-
err_unregister_hook:
2534+
err_register_hook:
2535+
nft_chain_del(chain);
2536+
err_chain_add:
2537+
nft_trans_destroy(trans);
2538+
err_trans:
25342539
nft_use_dec_restore(&table->use);
2535-
err_use:
2536-
nf_tables_unregister_hook(net, table, chain);
25372540
err_destroy_chain:
25382541
nf_tables_chain_destroy(ctx);
25392542

@@ -8455,9 +8458,9 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
84558458
u8 family = info->nfmsg->nfgen_family;
84568459
const struct nf_flowtable_type *type;
84578460
struct nft_flowtable *flowtable;
8458-
struct nft_hook *hook, *next;
84598461
struct net *net = info->net;
84608462
struct nft_table *table;
8463+
struct nft_trans *trans;
84618464
struct nft_ctx ctx;
84628465
int err;
84638466

@@ -8537,34 +8540,34 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
85378540
err = nft_flowtable_parse_hook(&ctx, nla, &flowtable_hook, flowtable,
85388541
extack, true);
85398542
if (err < 0)
8540-
goto err4;
8543+
goto err_flowtable_parse_hooks;
85418544

85428545
list_splice(&flowtable_hook.list, &flowtable->hook_list);
85438546
flowtable->data.priority = flowtable_hook.priority;
85448547
flowtable->hooknum = flowtable_hook.num;
85458548

8549+
trans = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
8550+
if (IS_ERR(trans)) {
8551+
err = PTR_ERR(trans);
8552+
goto err_flowtable_trans;
8553+
}
8554+
8555+
/* This must be LAST to ensure no packets are walking over this flowtable. */
85468556
err = nft_register_flowtable_net_hooks(ctx.net, table,
85478557
&flowtable->hook_list,
85488558
flowtable);
8549-
if (err < 0) {
8550-
nft_hooks_destroy(&flowtable->hook_list);
8551-
goto err4;
8552-
}
8553-
8554-
err = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
85558559
if (err < 0)
8556-
goto err5;
8560+
goto err_flowtable_hooks;
85578561

85588562
list_add_tail_rcu(&flowtable->list, &table->flowtables);
85598563

85608564
return 0;
8561-
err5:
8562-
list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
8563-
nft_unregister_flowtable_hook(net, flowtable, hook);
8564-
list_del_rcu(&hook->list);
8565-
kfree_rcu(hook, rcu);
8566-
}
8567-
err4:
8565+
8566+
err_flowtable_hooks:
8567+
nft_trans_destroy(trans);
8568+
err_flowtable_trans:
8569+
nft_hooks_destroy(&flowtable->hook_list);
8570+
err_flowtable_parse_hooks:
85688571
flowtable->data.type->free(&flowtable->data);
85698572
err3:
85708573
module_put(type->owner);

0 commit comments

Comments
 (0)