When a netnsamespace exits, the nf_tables pernet_ops will remove all rules.
However, there is one caveat:
Base chains that register ingress hooks will cause use-after-free:
device is already gone at that point.
The device event handlers prevent this from happening:
netns exit synthesizes unregister events for all devices.
However, an improper fix for a race condition made the notifiers a no-op
in case they get called from netns exit path, so revert that part.
This is safe now as the previous patch fixed nf_tables pernet ops
and device notifier initialisation ordering.
Fixes: 0a2cf5ee432c2 ("netfilter: nf_tables: close race between netns exit and
rmmod")
Signed-off-by: Florian Westphal <[email protected]>
---
net/netfilter/nf_tables_api.c | 6 +-----
net/netfilter/nft_chain_filter.c | 12 +++++++-----
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index b0ddc7897ca8..626c0f60b61d 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -5870,10 +5870,7 @@ static int nf_tables_flowtable_event(struct
notifier_block *this,
if (event != NETDEV_UNREGISTER)
return 0;
- net = maybe_get_net(dev_net(dev));
- if (!net)
- return 0;
-
+ net = dev_net(dev);
nfnl_lock(NFNL_SUBSYS_NFTABLES);
list_for_each_entry(table, &net->nft.tables, list) {
list_for_each_entry(flowtable, &table->flowtables, list) {
@@ -5881,7 +5878,6 @@ static int nf_tables_flowtable_event(struct
notifier_block *this,
}
}
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- put_net(net);
return NOTIFY_DONE;
}
diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c
index d21834bed805..fa6349916069 100644
--- a/net/netfilter/nft_chain_filter.c
+++ b/net/netfilter/nft_chain_filter.c
@@ -293,6 +293,13 @@ static void nft_netdev_event(unsigned long event, struct
net_device *dev,
if (strcmp(basechain->dev_name, dev->name) != 0)
return;
+ /* UNREGISTER events are also happpening on netns exit.
+ *
+ * Altough nf_tables core releases all tables/chains, only
+ * this event handler provides guarantee that
+ * basechain.ops->dev is still accessible, so we cannot
+ * skip exiting net namespaces.
+ */
__nft_release_basechain(ctx);
break;
case NETDEV_CHANGENAME:
@@ -318,10 +325,6 @@ static int nf_tables_netdev_event(struct notifier_block
*this,
event != NETDEV_CHANGENAME)
return NOTIFY_DONE;
- ctx.net = maybe_get_net(ctx.net);
- if (!ctx.net)
- return NOTIFY_DONE;
-
nfnl_lock(NFNL_SUBSYS_NFTABLES);
list_for_each_entry(table, &ctx.net->nft.tables, list) {
if (table->family != NFPROTO_NETDEV)
@@ -338,7 +341,6 @@ static int nf_tables_netdev_event(struct notifier_block
*this,
}
}
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- put_net(ctx.net);
return NOTIFY_DONE;
}
--
2.16.4
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html