Skip to content

Commit df05ef8

Browse files
committed
netfilter: nf_tables: release objects on netns destruction
We have to release the existing objects on netns removal otherwise we leak them. Chains are unregistered in first place to make sure no packets are walking on our rules and sets anymore. The object release happens by when we unregister the family via nft_release_afinfo() which is called from nft_unregister_afinfo() from the corresponding __net_exit path in every family. Reported-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 26a4d06 commit df05ef8

File tree

8 files changed

+52
-9
lines changed

8 files changed

+52
-9
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ struct nft_af_info {
880880
};
881881

882882
int nft_register_afinfo(struct net *, struct nft_af_info *);
883-
void nft_unregister_afinfo(struct nft_af_info *);
883+
void nft_unregister_afinfo(struct net *, struct nft_af_info *);
884884

885885
int nft_register_chain_type(const struct nf_chain_type *);
886886
void nft_unregister_chain_type(const struct nf_chain_type *);

net/bridge/netfilter/nf_tables_bridge.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static int nf_tables_bridge_init_net(struct net *net)
141141

142142
static void nf_tables_bridge_exit_net(struct net *net)
143143
{
144-
nft_unregister_afinfo(net->nft.bridge);
144+
nft_unregister_afinfo(net, net->nft.bridge);
145145
kfree(net->nft.bridge);
146146
}
147147

net/ipv4/netfilter/nf_tables_arp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static int nf_tables_arp_init_net(struct net *net)
5757

5858
static void nf_tables_arp_exit_net(struct net *net)
5959
{
60-
nft_unregister_afinfo(net->nft.arp);
60+
nft_unregister_afinfo(net, net->nft.arp);
6161
kfree(net->nft.arp);
6262
}
6363

net/ipv4/netfilter/nf_tables_ipv4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static int nf_tables_ipv4_init_net(struct net *net)
7878

7979
static void nf_tables_ipv4_exit_net(struct net *net)
8080
{
81-
nft_unregister_afinfo(net->nft.ipv4);
81+
nft_unregister_afinfo(net, net->nft.ipv4);
8282
kfree(net->nft.ipv4);
8383
}
8484

net/ipv6/netfilter/nf_tables_ipv6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static int nf_tables_ipv6_init_net(struct net *net)
7777

7878
static void nf_tables_ipv6_exit_net(struct net *net)
7979
{
80-
nft_unregister_afinfo(net->nft.ipv6);
80+
nft_unregister_afinfo(net, net->nft.ipv6);
8181
kfree(net->nft.ipv6);
8282
}
8383

net/netfilter/nf_tables_api.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,19 @@ int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
4141
}
4242
EXPORT_SYMBOL_GPL(nft_register_afinfo);
4343

44+
static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi);
45+
4446
/**
4547
* nft_unregister_afinfo - unregister nf_tables address family info
4648
*
4749
* @afi: address family info to unregister
4850
*
4951
* Unregister the address family for use with nf_tables.
5052
*/
51-
void nft_unregister_afinfo(struct nft_af_info *afi)
53+
void nft_unregister_afinfo(struct net *net, struct nft_af_info *afi)
5254
{
5355
nfnl_lock(NFNL_SUBSYS_NFTABLES);
56+
__nft_release_afinfo(net, afi);
5457
list_del_rcu(&afi->list);
5558
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
5659
}
@@ -4579,14 +4582,54 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
45794582
}
45804583
EXPORT_SYMBOL_GPL(nft_data_dump);
45814584

4582-
static int nf_tables_init_net(struct net *net)
4585+
static int __net_init nf_tables_init_net(struct net *net)
45834586
{
45844587
INIT_LIST_HEAD(&net->nft.af_info);
45854588
INIT_LIST_HEAD(&net->nft.commit_list);
45864589
net->nft.base_seq = 1;
45874590
return 0;
45884591
}
45894592

4593+
/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */
4594+
static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
4595+
{
4596+
struct nft_table *table, *nt;
4597+
struct nft_chain *chain, *nc;
4598+
struct nft_rule *rule, *nr;
4599+
struct nft_set *set, *ns;
4600+
struct nft_ctx ctx = {
4601+
.net = net,
4602+
.afi = afi,
4603+
};
4604+
4605+
list_for_each_entry_safe(table, nt, &afi->tables, list) {
4606+
list_for_each_entry(chain, &table->chains, list)
4607+
nf_tables_unregister_hooks(table, chain, afi->nops);
4608+
/* No packets are walking on these chains anymore. */
4609+
ctx.table = table;
4610+
list_for_each_entry(chain, &table->chains, list) {
4611+
ctx.chain = chain;
4612+
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
4613+
list_del(&rule->list);
4614+
chain->use--;
4615+
nf_tables_rule_destroy(&ctx, rule);
4616+
}
4617+
}
4618+
list_for_each_entry_safe(set, ns, &table->sets, list) {
4619+
list_del(&set->list);
4620+
table->use--;
4621+
nft_set_destroy(set);
4622+
}
4623+
list_for_each_entry_safe(chain, nc, &table->chains, list) {
4624+
list_del(&chain->list);
4625+
table->use--;
4626+
nf_tables_chain_destroy(chain);
4627+
}
4628+
list_del(&table->list);
4629+
nf_tables_table_destroy(&ctx);
4630+
}
4631+
}
4632+
45904633
static struct pernet_operations nf_tables_net_ops = {
45914634
.init = nf_tables_init_net,
45924635
};

net/netfilter/nf_tables_inet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static int __net_init nf_tables_inet_init_net(struct net *net)
5757

5858
static void __net_exit nf_tables_inet_exit_net(struct net *net)
5959
{
60-
nft_unregister_afinfo(net->nft.inet);
60+
nft_unregister_afinfo(net, net->nft.inet);
6161
kfree(net->nft.inet);
6262
}
6363

net/netfilter/nf_tables_netdev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static int nf_tables_netdev_init_net(struct net *net)
139139

140140
static void nf_tables_netdev_exit_net(struct net *net)
141141
{
142-
nft_unregister_afinfo(net->nft.netdev);
142+
nft_unregister_afinfo(net, net->nft.netdev);
143143
kfree(net->nft.netdev);
144144
}
145145

0 commit comments

Comments
 (0)