Commit 3c5cdb17 authored by Taehee Yoo's avatar Taehee Yoo Committed by Pablo Neira Ayuso

netfilter: nf_conncount: fix unexpected permanent node of list.

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. However, list may be left empty since node insertion
may fail eg.  allocaton problem. In order to solve this problem, GC
routine also finds zero count list without deleting node.

Fixes: cb2b36f5 ("netfilter: nf_conncount: Switch to plain list")
Signed-off-by: default avatarTaehee Yoo <ap420073@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 31568ec0
...@@ -144,8 +144,10 @@ static bool conn_free(struct nf_conncount_list *list, ...@@ -144,8 +144,10 @@ static bool conn_free(struct nf_conncount_list *list,
list->count--; list->count--;
conn->dead = true; conn->dead = true;
list_del_rcu(&conn->node); list_del_rcu(&conn->node);
if (list->count == 0) if (list->count == 0) {
list->dead = true;
free_entry = true; free_entry = true;
}
spin_unlock_bh(&list->list_lock); spin_unlock_bh(&list->list_lock);
call_rcu(&conn->rcu_head, __conn_free); call_rcu(&conn->rcu_head, __conn_free);
...@@ -248,7 +250,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list) ...@@ -248,7 +250,7 @@ void nf_conncount_list_init(struct nf_conncount_list *list)
{ {
spin_lock_init(&list->list_lock); spin_lock_init(&list->list_lock);
INIT_LIST_HEAD(&list->head); INIT_LIST_HEAD(&list->head);
list->count = 1; list->count = 0;
list->dead = false; list->dead = false;
} }
EXPORT_SYMBOL_GPL(nf_conncount_list_init); EXPORT_SYMBOL_GPL(nf_conncount_list_init);
...@@ -262,6 +264,7 @@ bool nf_conncount_gc_list(struct net *net, ...@@ -262,6 +264,7 @@ bool nf_conncount_gc_list(struct net *net,
struct nf_conn *found_ct; struct nf_conn *found_ct;
unsigned int collected = 0; unsigned int collected = 0;
bool free_entry = false; bool free_entry = false;
bool ret = false;
list_for_each_entry_safe(conn, conn_n, &list->head, node) { list_for_each_entry_safe(conn, conn_n, &list->head, node) {
found = find_or_evict(net, list, conn, &free_entry); found = find_or_evict(net, list, conn, &free_entry);
...@@ -291,7 +294,15 @@ bool nf_conncount_gc_list(struct net *net, ...@@ -291,7 +294,15 @@ bool nf_conncount_gc_list(struct net *net,
if (collected > CONNCOUNT_GC_MAX_NODES) if (collected > CONNCOUNT_GC_MAX_NODES)
return false; 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); EXPORT_SYMBOL_GPL(nf_conncount_gc_list);
...@@ -417,6 +428,7 @@ insert_tree(struct net *net, ...@@ -417,6 +428,7 @@ insert_tree(struct net *net,
nf_conncount_list_init(&rbconn->list); nf_conncount_list_init(&rbconn->list);
list_add(&conn->node, &rbconn->list.head); list_add(&conn->node, &rbconn->list.head);
count = 1; count = 1;
rbconn->list.count = count;
rb_link_node(&rbconn->node, parent, rbnode); rb_link_node(&rbconn->node, parent, rbnode);
rb_insert_color(&rbconn->node, root); rb_insert_color(&rbconn->node, root);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment