Skip to content

Commit fc01334

Browse files
Phil Sutterummakynes
authored andcommitted
netfilter: nf_tables: Tolerate chains with no remaining hooks
Do not drop a netdev-family chain if the last interface it is registered for vanishes. Users dumping and storing the ruleset upon shutdown to restore it upon next boot may otherwise lose the chain and all contained rules. They will still lose the list of devices, a later patch will fix that. For now, this aligns the event handler's behaviour with that for flowtables. The controversal situation at netns exit should be no problem here: event handler will unregister the hooks, core nftables cleanup code will drop the chain itself. Signed-off-by: Phil Sutter <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent bc87b75 commit fc01334

File tree

3 files changed

+7
-65
lines changed

3 files changed

+7
-65
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,8 +1238,6 @@ static inline bool nft_is_base_chain(const struct nft_chain *chain)
12381238
return chain->flags & NFT_CHAIN_BASE;
12391239
}
12401240

1241-
int __nft_release_basechain(struct nft_ctx *ctx);
1242-
12431241
unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
12441242

12451243
static inline bool nft_use_inc(u32 *use)

net/netfilter/nf_tables_api.c

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11741,47 +11741,6 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
1174111741
}
1174211742
EXPORT_SYMBOL_GPL(nft_data_dump);
1174311743

11744-
static void __nft_release_basechain_now(struct nft_ctx *ctx)
11745-
{
11746-
struct nft_rule *rule, *nr;
11747-
11748-
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
11749-
list_del(&rule->list);
11750-
nf_tables_rule_release(ctx, rule);
11751-
}
11752-
nf_tables_chain_destroy(ctx->chain);
11753-
}
11754-
11755-
int __nft_release_basechain(struct nft_ctx *ctx)
11756-
{
11757-
struct nft_rule *rule;
11758-
11759-
if (WARN_ON_ONCE(!nft_is_base_chain(ctx->chain)))
11760-
return 0;
11761-
11762-
nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
11763-
list_for_each_entry(rule, &ctx->chain->rules, list)
11764-
nft_use_dec(&ctx->chain->use);
11765-
11766-
nft_chain_del(ctx->chain);
11767-
nft_use_dec(&ctx->table->use);
11768-
11769-
if (!maybe_get_net(ctx->net)) {
11770-
__nft_release_basechain_now(ctx);
11771-
return 0;
11772-
}
11773-
11774-
/* wait for ruleset dumps to complete. Owning chain is no longer in
11775-
* lists, so new dumps can't find any of these rules anymore.
11776-
*/
11777-
synchronize_rcu();
11778-
11779-
__nft_release_basechain_now(ctx);
11780-
put_net(ctx->net);
11781-
return 0;
11782-
}
11783-
EXPORT_SYMBOL_GPL(__nft_release_basechain);
11784-
1178511744
static void __nft_release_hook(struct net *net, struct nft_table *table)
1178611745
{
1178711746
struct nft_flowtable *flowtable;

net/netfilter/nft_chain_filter.c

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -322,34 +322,19 @@ static void nft_netdev_event(unsigned long event, struct net_device *dev,
322322
struct nft_ctx *ctx)
323323
{
324324
struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
325-
struct nft_hook *hook, *found = NULL;
326-
int n = 0;
325+
struct nft_hook *hook;
327326

328327
list_for_each_entry(hook, &basechain->hook_list, list) {
329-
if (hook->ops.dev == dev)
330-
found = hook;
331-
332-
n++;
333-
}
334-
if (!found)
335-
return;
328+
if (hook->ops.dev != dev)
329+
continue;
336330

337-
if (n > 1) {
338331
if (!(ctx->chain->table->flags & NFT_TABLE_F_DORMANT))
339-
nf_unregister_net_hook(ctx->net, &found->ops);
332+
nf_unregister_net_hook(ctx->net, &hook->ops);
340333

341-
list_del_rcu(&found->list);
342-
kfree_rcu(found, rcu);
343-
return;
334+
list_del_rcu(&hook->list);
335+
kfree_rcu(hook, rcu);
336+
break;
344337
}
345-
346-
/* UNREGISTER events are also happening on netns exit.
347-
*
348-
* Although nf_tables core releases all tables/chains, only this event
349-
* handler provides guarantee that hook->ops.dev is still accessible,
350-
* so we cannot skip exiting net namespaces.
351-
*/
352-
__nft_release_basechain(ctx);
353338
}
354339

355340
static int nf_tables_netdev_event(struct notifier_block *this,

0 commit comments

Comments
 (0)