Skip to content

Commit 7b48564

Browse files
Phil Sutterummakynes
authored andcommitted
netfilter: nf_tables: Handle NETDEV_CHANGENAME events
For the sake of simplicity, treat them like consecutive NETDEV_REGISTER and NETDEV_UNREGISTER events. If the new name matches a hook spec and registration fails, escalate the error and keep things as they are. To avoid unregistering the newly registered hook again during the following fake NETDEV_UNREGISTER event, leave hooks alone if their interface spec matches the new name. Note how this patch also skips for NETDEV_REGISTER if the device is already registered. This is not yet possible as the new name would have to match the old one. This will change with wildcard interface specs, though. Signed-off-by: Phil Sutter <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 9669c11 commit 7b48564

File tree

2 files changed

+48
-18
lines changed

2 files changed

+48
-18
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9690,16 +9690,20 @@ struct nf_hook_ops *nft_hook_find_ops_rcu(const struct nft_hook *hook,
96909690
EXPORT_SYMBOL_GPL(nft_hook_find_ops_rcu);
96919691

96929692
static int nft_flowtable_event(unsigned long event, struct net_device *dev,
9693-
struct nft_flowtable *flowtable)
9693+
struct nft_flowtable *flowtable, bool changename)
96949694
{
96959695
struct nf_hook_ops *ops;
96969696
struct nft_hook *hook;
9697+
bool match;
96979698

96989699
list_for_each_entry(hook, &flowtable->hook_list, list) {
9700+
ops = nft_hook_find_ops(hook, dev);
9701+
match = !strcmp(hook->ifname, dev->name);
9702+
96999703
switch (event) {
97009704
case NETDEV_UNREGISTER:
9701-
ops = nft_hook_find_ops(hook, dev);
9702-
if (!ops)
9705+
/* NOP if not found or new name still matching */
9706+
if (!ops || (changename && match))
97039707
continue;
97049708

97059709
/* flow_offload_netdev_event() cleans up entries for us. */
@@ -9709,7 +9713,8 @@ static int nft_flowtable_event(unsigned long event, struct net_device *dev,
97099713
kfree_rcu(ops, rcu);
97109714
break;
97119715
case NETDEV_REGISTER:
9712-
if (strcmp(hook->ifname, dev->name))
9716+
/* NOP if not matching or already registered */
9717+
if (!match || (changename && ops))
97139718
continue;
97149719

97159720
ops = kzalloc(sizeof(struct nf_hook_ops),
@@ -9737,15 +9742,17 @@ static int nft_flowtable_event(unsigned long event, struct net_device *dev,
97379742
}
97389743

97399744
static int __nf_tables_flowtable_event(unsigned long event,
9740-
struct net_device *dev)
9745+
struct net_device *dev,
9746+
bool changename)
97419747
{
97429748
struct nftables_pernet *nft_net = nft_pernet(dev_net(dev));
97439749
struct nft_flowtable *flowtable;
97449750
struct nft_table *table;
97459751

97469752
list_for_each_entry(table, &nft_net->tables, list) {
97479753
list_for_each_entry(flowtable, &table->flowtables, list) {
9748-
if (nft_flowtable_event(event, dev, flowtable))
9754+
if (nft_flowtable_event(event, dev,
9755+
flowtable, changename))
97499756
return 1;
97509757
}
97519758
}
@@ -9761,16 +9768,24 @@ static int nf_tables_flowtable_event(struct notifier_block *this,
97619768
struct net *net;
97629769

97639770
if (event != NETDEV_REGISTER &&
9764-
event != NETDEV_UNREGISTER)
9771+
event != NETDEV_UNREGISTER &&
9772+
event != NETDEV_CHANGENAME)
97659773
return NOTIFY_DONE;
97669774

97679775
net = dev_net(dev);
97689776
nft_net = nft_pernet(net);
97699777
mutex_lock(&nft_net->commit_mutex);
97709778

9771-
if (__nf_tables_flowtable_event(event, dev))
9779+
if (event == NETDEV_CHANGENAME) {
9780+
if (__nf_tables_flowtable_event(NETDEV_REGISTER, dev, true)) {
9781+
ret = NOTIFY_BAD;
9782+
goto out_unlock;
9783+
}
9784+
__nf_tables_flowtable_event(NETDEV_UNREGISTER, dev, true);
9785+
} else if (__nf_tables_flowtable_event(event, dev, false)) {
97729786
ret = NOTIFY_BAD;
9773-
9787+
}
9788+
out_unlock:
97749789
mutex_unlock(&nft_net->commit_mutex);
97759790
return ret;
97769791
}

net/netfilter/nft_chain_filter.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -319,17 +319,21 @@ static const struct nft_chain_type nft_chain_filter_netdev = {
319319
};
320320

321321
static int nft_netdev_event(unsigned long event, struct net_device *dev,
322-
struct nft_base_chain *basechain)
322+
struct nft_base_chain *basechain, bool changename)
323323
{
324324
struct nft_table *table = basechain->chain.table;
325325
struct nf_hook_ops *ops;
326326
struct nft_hook *hook;
327+
bool match;
327328

328329
list_for_each_entry(hook, &basechain->hook_list, list) {
330+
ops = nft_hook_find_ops(hook, dev);
331+
match = !strcmp(hook->ifname, dev->name);
332+
329333
switch (event) {
330334
case NETDEV_UNREGISTER:
331-
ops = nft_hook_find_ops(hook, dev);
332-
if (!ops)
335+
/* NOP if not found or new name still matching */
336+
if (!ops || (changename && match))
333337
continue;
334338

335339
if (!(table->flags & NFT_TABLE_F_DORMANT))
@@ -339,7 +343,8 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev,
339343
kfree_rcu(ops, rcu);
340344
break;
341345
case NETDEV_REGISTER:
342-
if (strcmp(hook->ifname, dev->name))
346+
/* NOP if not matching or already registered */
347+
if (!match || (changename && ops))
343348
continue;
344349

345350
ops = kmemdup(&basechain->ops,
@@ -363,7 +368,9 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev,
363368
return 0;
364369
}
365370

366-
static int __nf_tables_netdev_event(unsigned long event, struct net_device *dev)
371+
static int __nf_tables_netdev_event(unsigned long event,
372+
struct net_device *dev,
373+
bool changename)
367374
{
368375
struct nft_base_chain *basechain;
369376
struct nftables_pernet *nft_net;
@@ -385,7 +392,7 @@ static int __nf_tables_netdev_event(unsigned long event, struct net_device *dev)
385392
basechain->ops.hooknum != NF_INET_INGRESS)
386393
continue;
387394

388-
if (nft_netdev_event(event, dev, basechain))
395+
if (nft_netdev_event(event, dev, basechain, changename))
389396
return 1;
390397
}
391398
}
@@ -400,15 +407,23 @@ static int nf_tables_netdev_event(struct notifier_block *this,
400407
int ret = NOTIFY_DONE;
401408

402409
if (event != NETDEV_REGISTER &&
403-
event != NETDEV_UNREGISTER)
410+
event != NETDEV_UNREGISTER &&
411+
event != NETDEV_CHANGENAME)
404412
return NOTIFY_DONE;
405413

406414
nft_net = nft_pernet(dev_net(dev));
407415
mutex_lock(&nft_net->commit_mutex);
408416

409-
if (__nf_tables_netdev_event(event, dev))
417+
if (event == NETDEV_CHANGENAME) {
418+
if (__nf_tables_netdev_event(NETDEV_REGISTER, dev, true)) {
419+
ret = NOTIFY_BAD;
420+
goto out_unlock;
421+
}
422+
__nf_tables_netdev_event(NETDEV_UNREGISTER, dev, true);
423+
} else if (__nf_tables_netdev_event(event, dev, false)) {
410424
ret = NOTIFY_BAD;
411-
425+
}
426+
out_unlock:
412427
mutex_unlock(&nft_net->commit_mutex);
413428
return ret;
414429
}

0 commit comments

Comments
 (0)