blob: 3cbe6abf508b5586166913d1e985db30abaf7c28 [file] [log] [blame]
From 665e205c16c1f902ac6763b8ce8a0a3a1dcefe59 Mon Sep 17 00:00:00 2001
From: "Vitaly E. Lavrov" <lve@guap.ru>
Date: Mon, 24 Dec 2012 13:55:20 +0100
Subject: netfilter: xt_recent: fix namespace destroy path
From: "Vitaly E. Lavrov" <lve@guap.ru>
commit 665e205c16c1f902ac6763b8ce8a0a3a1dcefe59 upstream.
recent_net_exit() is called before recent_mt_destroy() in the
destroy path of network namespaces. Make sure there are no entries
in the parent proc entry xt_recent before removing it.
Signed-off-by: Vitaly E. Lavrov <lve@guap.ru>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/netfilter/xt_recent.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -431,7 +431,8 @@ static void recent_mt_destroy(const stru
list_del(&t->list);
spin_unlock_bh(&recent_lock);
#ifdef CONFIG_PROC_FS
- remove_proc_entry(t->name, recent_net->xt_recent);
+ if (recent_net->xt_recent != NULL)
+ remove_proc_entry(t->name, recent_net->xt_recent);
#endif
recent_table_flush(t);
kfree(t);
@@ -615,6 +616,20 @@ static int __net_init recent_proc_net_in
static void __net_exit recent_proc_net_exit(struct net *net)
{
+ struct recent_net *recent_net = recent_pernet(net);
+ struct recent_table *t;
+
+ /* recent_net_exit() is called before recent_mt_destroy(). Make sure
+ * that the parent xt_recent proc entry is is empty before trying to
+ * remove it.
+ */
+ spin_lock_bh(&recent_lock);
+ list_for_each_entry(t, &recent_net->tables, list)
+ remove_proc_entry(t->name, recent_net->xt_recent);
+
+ recent_net->xt_recent = NULL;
+ spin_unlock_bh(&recent_lock);
+
proc_net_remove(net, "xt_recent");
}
#else
@@ -638,9 +653,6 @@ static int __net_init recent_net_init(st
static void __net_exit recent_net_exit(struct net *net)
{
- struct recent_net *recent_net = recent_pernet(net);
-
- BUG_ON(!list_empty(&recent_net->tables));
recent_proc_net_exit(net);
}