diff options
Diffstat (limited to '')
-rw-r--r-- | net/netfilter/nf_tables_api.c | 33 | ||||
-rw-r--r-- | net/netfilter/nft_chain_filter.c | 33 |
2 files changed, 48 insertions, 18 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 713ea0e48772..452f8a42d5e6 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -9690,16 +9690,20 @@ struct nf_hook_ops *nft_hook_find_ops_rcu(const struct nft_hook *hook, EXPORT_SYMBOL_GPL(nft_hook_find_ops_rcu); static int nft_flowtable_event(unsigned long event, struct net_device *dev, - struct nft_flowtable *flowtable) + struct nft_flowtable *flowtable, bool changename) { struct nf_hook_ops *ops; struct nft_hook *hook; + bool match; list_for_each_entry(hook, &flowtable->hook_list, list) { + ops = nft_hook_find_ops(hook, dev); + match = !strcmp(hook->ifname, dev->name); + switch (event) { case NETDEV_UNREGISTER: - ops = nft_hook_find_ops(hook, dev); - if (!ops) + /* NOP if not found or new name still matching */ + if (!ops || (changename && match)) continue; /* 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, kfree_rcu(ops, rcu); break; case NETDEV_REGISTER: - if (strcmp(hook->ifname, dev->name)) + /* NOP if not matching or already registered */ + if (!match || (changename && ops)) continue; ops = kzalloc(sizeof(struct nf_hook_ops), @@ -9737,7 +9742,8 @@ static int nft_flowtable_event(unsigned long event, struct net_device *dev, } static int __nf_tables_flowtable_event(unsigned long event, - struct net_device *dev) + struct net_device *dev, + bool changename) { struct nftables_pernet *nft_net = nft_pernet(dev_net(dev)); struct nft_flowtable *flowtable; @@ -9745,7 +9751,8 @@ static int __nf_tables_flowtable_event(unsigned long event, list_for_each_entry(table, &nft_net->tables, list) { list_for_each_entry(flowtable, &table->flowtables, list) { - if (nft_flowtable_event(event, dev, flowtable)) + if (nft_flowtable_event(event, dev, + flowtable, changename)) return 1; } } @@ -9761,16 +9768,24 @@ static int nf_tables_flowtable_event(struct notifier_block *this, struct net *net; if (event != NETDEV_REGISTER && - event != NETDEV_UNREGISTER) + event != NETDEV_UNREGISTER && + event != NETDEV_CHANGENAME) return NOTIFY_DONE; net = dev_net(dev); nft_net = nft_pernet(net); mutex_lock(&nft_net->commit_mutex); - if (__nf_tables_flowtable_event(event, dev)) + if (event == NETDEV_CHANGENAME) { + if (__nf_tables_flowtable_event(NETDEV_REGISTER, dev, true)) { + ret = NOTIFY_BAD; + goto out_unlock; + } + __nf_tables_flowtable_event(NETDEV_UNREGISTER, dev, true); + } else if (__nf_tables_flowtable_event(event, dev, false)) { ret = NOTIFY_BAD; - + } +out_unlock: mutex_unlock(&nft_net->commit_mutex); return ret; } diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c index 7795dff13408..b59f8be6370e 100644 --- a/net/netfilter/nft_chain_filter.c +++ b/net/netfilter/nft_chain_filter.c @@ -319,17 +319,21 @@ static const struct nft_chain_type nft_chain_filter_netdev = { }; static int nft_netdev_event(unsigned long event, struct net_device *dev, - struct nft_base_chain *basechain) + struct nft_base_chain *basechain, bool changename) { struct nft_table *table = basechain->chain.table; struct nf_hook_ops *ops; struct nft_hook *hook; + bool match; list_for_each_entry(hook, &basechain->hook_list, list) { + ops = nft_hook_find_ops(hook, dev); + match = !strcmp(hook->ifname, dev->name); + switch (event) { case NETDEV_UNREGISTER: - ops = nft_hook_find_ops(hook, dev); - if (!ops) + /* NOP if not found or new name still matching */ + if (!ops || (changename && match)) continue; if (!(table->flags & NFT_TABLE_F_DORMANT)) @@ -339,7 +343,8 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev, kfree_rcu(ops, rcu); break; case NETDEV_REGISTER: - if (strcmp(hook->ifname, dev->name)) + /* NOP if not matching or already registered */ + if (!match || (changename && ops)) continue; ops = kmemdup(&basechain->ops, @@ -363,7 +368,9 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev, return 0; } -static int __nf_tables_netdev_event(unsigned long event, struct net_device *dev) +static int __nf_tables_netdev_event(unsigned long event, + struct net_device *dev, + bool changename) { struct nft_base_chain *basechain; struct nftables_pernet *nft_net; @@ -385,7 +392,7 @@ static int __nf_tables_netdev_event(unsigned long event, struct net_device *dev) basechain->ops.hooknum != NF_INET_INGRESS) continue; - if (nft_netdev_event(event, dev, basechain)) + if (nft_netdev_event(event, dev, basechain, changename)) return 1; } } @@ -400,15 +407,23 @@ static int nf_tables_netdev_event(struct notifier_block *this, int ret = NOTIFY_DONE; if (event != NETDEV_REGISTER && - event != NETDEV_UNREGISTER) + event != NETDEV_UNREGISTER && + event != NETDEV_CHANGENAME) return NOTIFY_DONE; nft_net = nft_pernet(dev_net(dev)); mutex_lock(&nft_net->commit_mutex); - if (__nf_tables_netdev_event(event, dev)) + if (event == NETDEV_CHANGENAME) { + if (__nf_tables_netdev_event(NETDEV_REGISTER, dev, true)) { + ret = NOTIFY_BAD; + goto out_unlock; + } + __nf_tables_netdev_event(NETDEV_UNREGISTER, dev, true); + } else if (__nf_tables_netdev_event(event, dev, false)) { ret = NOTIFY_BAD; - + } +out_unlock: mutex_unlock(&nft_net->commit_mutex); return ret; } |