aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2015-12-15 13:40:49 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2015-12-28 12:34:35 -0500
commit5ebe0b0eec9d6f703b137f9b938c52f7b91dd9d6 (patch)
tree3bce71064195708c73697ffba15606f43256561e /net/netfilter
parentdf05ef874b284d833c2d9795a6350c6a373ab6c9 (diff)
netfilter: nf_tables: destroy basechain and rules on netdevice removal
If the netdevice is destroyed, the resources that are attached should be released too as they belong to the device that is now gone. Suggested-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_tables_api.c31
-rw-r--r--net/netfilter/nf_tables_netdev.c45
2 files changed, 43 insertions, 33 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 852273110275..5729844e1d46 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -131,8 +131,8 @@ static void nft_trans_destroy(struct nft_trans *trans)
131 kfree(trans); 131 kfree(trans);
132} 132}
133 133
134int nft_register_basechain(struct nft_base_chain *basechain, 134static int nft_register_basechain(struct nft_base_chain *basechain,
135 unsigned int hook_nops) 135 unsigned int hook_nops)
136{ 136{
137 struct net *net = read_pnet(&basechain->pnet); 137 struct net *net = read_pnet(&basechain->pnet);
138 138
@@ -141,10 +141,9 @@ int nft_register_basechain(struct nft_base_chain *basechain,
141 141
142 return nf_register_net_hooks(net, basechain->ops, hook_nops); 142 return nf_register_net_hooks(net, basechain->ops, hook_nops);
143} 143}
144EXPORT_SYMBOL_GPL(nft_register_basechain);
145 144
146void nft_unregister_basechain(struct nft_base_chain *basechain, 145static void nft_unregister_basechain(struct nft_base_chain *basechain,
147 unsigned int hook_nops) 146 unsigned int hook_nops)
148{ 147{
149 struct net *net = read_pnet(&basechain->pnet); 148 struct net *net = read_pnet(&basechain->pnet);
150 149
@@ -153,7 +152,6 @@ void nft_unregister_basechain(struct nft_base_chain *basechain,
153 152
154 nf_unregister_net_hooks(net, basechain->ops, hook_nops); 153 nf_unregister_net_hooks(net, basechain->ops, hook_nops);
155} 154}
156EXPORT_SYMBOL_GPL(nft_unregister_basechain);
157 155
158static int nf_tables_register_hooks(const struct nft_table *table, 156static int nf_tables_register_hooks(const struct nft_table *table,
159 struct nft_chain *chain, 157 struct nft_chain *chain,
@@ -4590,6 +4588,27 @@ static int __net_init nf_tables_init_net(struct net *net)
4590 return 0; 4588 return 0;
4591} 4589}
4592 4590
4591int __nft_release_basechain(struct nft_ctx *ctx)
4592{
4593 struct nft_rule *rule, *nr;
4594
4595 BUG_ON(!(ctx->chain->flags & NFT_BASE_CHAIN));
4596
4597 nf_tables_unregister_hooks(ctx->chain->table, ctx->chain,
4598 ctx->afi->nops);
4599 list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
4600 list_del(&rule->list);
4601 ctx->chain->use--;
4602 nf_tables_rule_destroy(ctx, rule);
4603 }
4604 list_del(&ctx->chain->list);
4605 ctx->table->use--;
4606 nf_tables_chain_destroy(ctx->chain);
4607
4608 return 0;
4609}
4610EXPORT_SYMBOL_GPL(__nft_release_basechain);
4611
4593/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */ 4612/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */
4594static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi) 4613static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
4595{ 4614{
diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c
index 2bfd1fbccec8..3e9c87b961ba 100644
--- a/net/netfilter/nf_tables_netdev.c
+++ b/net/netfilter/nf_tables_netdev.c
@@ -156,35 +156,17 @@ static const struct nf_chain_type nft_filter_chain_netdev = {
156 .hook_mask = (1 << NF_NETDEV_INGRESS), 156 .hook_mask = (1 << NF_NETDEV_INGRESS),
157}; 157};
158 158
159static void nft_netdev_event(unsigned long event, struct nft_af_info *afi, 159static void nft_netdev_event(unsigned long event, struct net_device *dev,
160 struct net_device *dev, struct nft_table *table, 160 struct nft_ctx *ctx)
161 struct nft_base_chain *basechain)
162{ 161{
163 switch (event) { 162 struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
164 case NETDEV_REGISTER:
165 if (strcmp(basechain->dev_name, dev->name) != 0)
166 return;
167 163
168 BUG_ON(!(basechain->flags & NFT_BASECHAIN_DISABLED)); 164 switch (event) {
169
170 dev_hold(dev);
171 basechain->ops[0].dev = dev;
172 basechain->flags &= ~NFT_BASECHAIN_DISABLED;
173 if (!(table->flags & NFT_TABLE_F_DORMANT))
174 nft_register_basechain(basechain, afi->nops);
175 break;
176 case NETDEV_UNREGISTER: 165 case NETDEV_UNREGISTER:
177 if (strcmp(basechain->dev_name, dev->name) != 0) 166 if (strcmp(basechain->dev_name, dev->name) != 0)
178 return; 167 return;
179 168
180 BUG_ON(basechain->flags & NFT_BASECHAIN_DISABLED); 169 __nft_release_basechain(ctx);
181
182 if (!(table->flags & NFT_TABLE_F_DORMANT))
183 nft_unregister_basechain(basechain, afi->nops);
184
185 dev_put(basechain->ops[0].dev);
186 basechain->ops[0].dev = NULL;
187 basechain->flags |= NFT_BASECHAIN_DISABLED;
188 break; 170 break;
189 case NETDEV_CHANGENAME: 171 case NETDEV_CHANGENAME:
190 if (dev->ifindex != basechain->ops[0].dev->ifindex) 172 if (dev->ifindex != basechain->ops[0].dev->ifindex)
@@ -201,20 +183,29 @@ static int nf_tables_netdev_event(struct notifier_block *this,
201 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 183 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
202 struct nft_af_info *afi; 184 struct nft_af_info *afi;
203 struct nft_table *table; 185 struct nft_table *table;
204 struct nft_chain *chain; 186 struct nft_chain *chain, *nr;
187 struct nft_ctx ctx = {
188 .net = dev_net(dev),
189 };
190
191 if (event != NETDEV_UNREGISTER &&
192 event != NETDEV_CHANGENAME)
193 return NOTIFY_DONE;
205 194
206 nfnl_lock(NFNL_SUBSYS_NFTABLES); 195 nfnl_lock(NFNL_SUBSYS_NFTABLES);
207 list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) { 196 list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) {
197 ctx.afi = afi;
208 if (afi->family != NFPROTO_NETDEV) 198 if (afi->family != NFPROTO_NETDEV)
209 continue; 199 continue;
210 200
211 list_for_each_entry(table, &afi->tables, list) { 201 list_for_each_entry(table, &afi->tables, list) {
212 list_for_each_entry(chain, &table->chains, list) { 202 ctx.table = table;
203 list_for_each_entry_safe(chain, nr, &table->chains, list) {
213 if (!(chain->flags & NFT_BASE_CHAIN)) 204 if (!(chain->flags & NFT_BASE_CHAIN))
214 continue; 205 continue;
215 206
216 nft_netdev_event(event, afi, dev, table, 207 ctx.chain = chain;
217 nft_base_chain(chain)); 208 nft_netdev_event(event, dev, &ctx);
218 } 209 }
219 } 210 }
220 } 211 }