Skip to content

Commit 835b803

Browse files
committed
netfilter: nf_tables_netdev: unregister hooks on net_device removal
In case the net_device is gone, we have to unregister the hooks and put back the reference on the net_device object. Once it comes back, register them again. This also covers the device rename case. This patch also adds a new flag to indicate that the basechain is disabled, so their hooks are not registered. This flag is used by the netdev family to handle the case where the net_device object is gone. Currently this flag is not exposed to userspace. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent d8ee8f7 commit 835b803

File tree

3 files changed

+94
-4
lines changed

3 files changed

+94
-4
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,7 @@ struct nft_stats {
781781
};
782782

783783
#define NFT_HOOK_OPS_MAX 2
784+
#define NFT_BASECHAIN_DISABLED (1 << 0)
784785

785786
/**
786787
* struct nft_base_chain - nf_tables base chain
@@ -798,6 +799,7 @@ struct nft_base_chain {
798799
possible_net_t pnet;
799800
const struct nf_chain_type *type;
800801
u8 policy;
802+
u8 flags;
801803
struct nft_stats __percpu *stats;
802804
struct nft_chain chain;
803805
char dev_name[IFNAMSIZ];
@@ -808,6 +810,11 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai
808810
return container_of(chain, struct nft_base_chain, chain);
809811
}
810812

813+
int nft_register_basechain(struct nft_base_chain *basechain,
814+
unsigned int hook_nops);
815+
void nft_unregister_basechain(struct nft_base_chain *basechain,
816+
unsigned int hook_nops);
817+
811818
unsigned int nft_do_chain(struct nft_pktinfo *pkt,
812819
const struct nf_hook_ops *ops);
813820

net/netfilter/nf_tables_api.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,25 @@ static void nft_trans_destroy(struct nft_trans *trans)
127127
kfree(trans);
128128
}
129129

130-
static int nft_register_basechain(struct nft_base_chain *basechain,
131-
unsigned int hook_nops)
130+
int nft_register_basechain(struct nft_base_chain *basechain,
131+
unsigned int hook_nops)
132132
{
133+
if (basechain->flags & NFT_BASECHAIN_DISABLED)
134+
return 0;
135+
133136
return nf_register_hooks(basechain->ops, hook_nops);
134137
}
138+
EXPORT_SYMBOL_GPL(nft_register_basechain);
135139

136-
static void nft_unregister_basechain(struct nft_base_chain *basechain,
137-
unsigned int hook_nops)
140+
void nft_unregister_basechain(struct nft_base_chain *basechain,
141+
unsigned int hook_nops)
138142
{
143+
if (basechain->flags & NFT_BASECHAIN_DISABLED)
144+
return;
145+
139146
nf_unregister_hooks(basechain->ops, hook_nops);
140147
}
148+
EXPORT_SYMBOL_GPL(nft_unregister_basechain);
141149

142150
static int nf_tables_register_hooks(const struct nft_table *table,
143151
struct nft_chain *chain,

net/netfilter/nf_tables_netdev.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/init.h>
1010
#include <linux/module.h>
11+
#include <linux/netdevice.h>
1112
#include <net/netfilter/nf_tables.h>
1213
#include <linux/ip.h>
1314
#include <linux/ipv6.h>
@@ -157,6 +158,77 @@ static const struct nf_chain_type nft_filter_chain_netdev = {
157158
.hook_mask = (1 << NF_NETDEV_INGRESS),
158159
};
159160

161+
static void nft_netdev_event(unsigned long event, struct nft_af_info *afi,
162+
struct net_device *dev, struct nft_table *table,
163+
struct nft_base_chain *basechain)
164+
{
165+
switch (event) {
166+
case NETDEV_REGISTER:
167+
if (strcmp(basechain->dev_name, dev->name) != 0)
168+
return;
169+
170+
BUG_ON(!(basechain->flags & NFT_BASECHAIN_DISABLED));
171+
172+
dev_hold(dev);
173+
basechain->ops[0].dev = dev;
174+
basechain->flags &= ~NFT_BASECHAIN_DISABLED;
175+
if (!(table->flags & NFT_TABLE_F_DORMANT))
176+
nft_register_basechain(basechain, afi->nops);
177+
break;
178+
case NETDEV_UNREGISTER:
179+
if (strcmp(basechain->dev_name, dev->name) != 0)
180+
return;
181+
182+
BUG_ON(basechain->flags & NFT_BASECHAIN_DISABLED);
183+
184+
if (!(table->flags & NFT_TABLE_F_DORMANT))
185+
nft_unregister_basechain(basechain, afi->nops);
186+
187+
dev_put(basechain->ops[0].dev);
188+
basechain->ops[0].dev = NULL;
189+
basechain->flags |= NFT_BASECHAIN_DISABLED;
190+
break;
191+
case NETDEV_CHANGENAME:
192+
if (dev->ifindex != basechain->ops[0].dev->ifindex)
193+
return;
194+
195+
strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
196+
break;
197+
}
198+
}
199+
200+
static int nf_tables_netdev_event(struct notifier_block *this,
201+
unsigned long event, void *ptr)
202+
{
203+
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
204+
struct nft_af_info *afi;
205+
struct nft_table *table;
206+
struct nft_chain *chain;
207+
208+
nfnl_lock(NFNL_SUBSYS_NFTABLES);
209+
list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) {
210+
if (afi->family != NFPROTO_NETDEV)
211+
continue;
212+
213+
list_for_each_entry(table, &afi->tables, list) {
214+
list_for_each_entry(chain, &table->chains, list) {
215+
if (!(chain->flags & NFT_BASE_CHAIN))
216+
continue;
217+
218+
nft_netdev_event(event, afi, dev, table,
219+
nft_base_chain(chain));
220+
}
221+
}
222+
}
223+
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
224+
225+
return NOTIFY_DONE;
226+
}
227+
228+
static struct notifier_block nf_tables_netdev_notifier = {
229+
.notifier_call = nf_tables_netdev_event,
230+
};
231+
160232
static int __init nf_tables_netdev_init(void)
161233
{
162234
int ret;
@@ -166,11 +238,14 @@ static int __init nf_tables_netdev_init(void)
166238
if (ret < 0)
167239
nft_unregister_chain_type(&nft_filter_chain_netdev);
168240

241+
register_netdevice_notifier(&nf_tables_netdev_notifier);
242+
169243
return ret;
170244
}
171245

172246
static void __exit nf_tables_netdev_exit(void)
173247
{
248+
unregister_netdevice_notifier(&nf_tables_netdev_notifier);
174249
unregister_pernet_subsys(&nf_tables_netdev_net_ops);
175250
nft_unregister_chain_type(&nft_filter_chain_netdev);
176251
}

0 commit comments

Comments
 (0)