diff mbox series

[nf,v2,3/3] netfilter: nf_conncount: fix unexpected permanent node of list.

Message ID 20181104184439.19766-1-ap420073@gmail.com
State Accepted
Delegated to: Pablo Neira
Headers show
Series netfilter: nf_conncount: fix bugs in conn_free | expand

Commit Message

Taehee Yoo Nov. 4, 2018, 6:44 p.m. UTC
When list->count is 0, the list is deleted by GC.
But list->count is never reached 0. because Initial count value is 1
and it is increased when node is inserted.
So that initial value of list->count should be 0.

Originally GC always finds zero count list through deleting node and
decreasing count. it has problem that it couldn't find lists that
didn't insert nodes(by allocating problem, etc...).
In order to solve this problem, GC routine also finds zero count list
without deleting node.

v2:
 - Use spin_lock_bh() in nf_conncount_add() (Pablo Neira Ayuso)
 - Add Third patch.
v1: Initial patch

Fixes: cb2b36f5a97d ("netfilter: nf_conncount: Switch to plain list")
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
---
 net/netfilter/nf_conncount.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/net/netfilter/nf_conncount.c b/net/netfilter/nf_conncount.c
index cb33709138df..b5dc749112a1 100644
--- a/net/netfilter/nf_conncount.c
+++ b/net/netfilter/nf_conncount.c
@@ -144,8 +144,10 @@  static bool conn_free(struct nf_conncount_list *list,
 	list->count--;
 	conn->dead = true;
 	list_del_rcu(&conn->node);
-	if (list->count == 0)
+	if (list->count == 0) {
+		list->dead = true;
 		free_entry = true;
+	}
 
 	spin_unlock_bh(&list->list_lock);
 	call_rcu(&conn->rcu_head, __conn_free);
@@ -248,7 +250,7 @@  void nf_conncount_list_init(struct nf_conncount_list *list)
 {
 	spin_lock_init(&list->list_lock);
 	INIT_LIST_HEAD(&list->head);
-	list->count = 1;
+	list->count = 0;
 	list->dead = false;
 }
 EXPORT_SYMBOL_GPL(nf_conncount_list_init);
@@ -262,6 +264,7 @@  bool nf_conncount_gc_list(struct net *net,
 	struct nf_conn *found_ct;
 	unsigned int collected = 0;
 	bool free_entry = false;
+	bool ret = false;
 
 	list_for_each_entry_safe(conn, conn_n, &list->head, node) {
 		found = find_or_evict(net, list, conn, &free_entry);
@@ -291,7 +294,14 @@  bool nf_conncount_gc_list(struct net *net,
 		if (collected > CONNCOUNT_GC_MAX_NODES)
 			return false;
 	}
-	return false;
+
+	spin_lock_bh(&list->list_lock);
+	if (!list->count) {
+		list->dead = true;
+		ret = true;
+	}
+	spin_unlock_bh(&list->list_lock);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(nf_conncount_gc_list);
 
@@ -417,6 +427,7 @@  insert_tree(struct net *net,
 	nf_conncount_list_init(&rbconn->list);
 	list_add(&conn->node, &rbconn->list.head);
 	count = 1;
+	rbconn->list.count = count;
 
 	rb_link_node(&rbconn->node, parent, rbnode);
 	rb_insert_color(&rbconn->node, root);