Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: cb2b36f5a97d ("netfilter: nf_conncount: Switch to plain list")
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Taehee Yoo and committed by
Pablo Neira Ayuso
3c5cdb17 31568ec0

+15 -3
+15 -3
net/netfilter/nf_conncount.c
··· 144 144 list->count--; 145 145 conn->dead = true; 146 146 list_del_rcu(&conn->node); 147 - if (list->count == 0) 147 + if (list->count == 0) { 148 + list->dead = true; 148 149 free_entry = true; 150 + } 149 151 150 152 spin_unlock_bh(&list->list_lock); 151 153 call_rcu(&conn->rcu_head, __conn_free); ··· 250 248 { 251 249 spin_lock_init(&list->list_lock); 252 250 INIT_LIST_HEAD(&list->head); 253 - list->count = 1; 251 + list->count = 0; 254 252 list->dead = false; 255 253 } 256 254 EXPORT_SYMBOL_GPL(nf_conncount_list_init); ··· 264 262 struct nf_conn *found_ct; 265 263 unsigned int collected = 0; 266 264 bool free_entry = false; 265 + bool ret = false; 267 266 268 267 list_for_each_entry_safe(conn, conn_n, &list->head, node) { 269 268 found = find_or_evict(net, list, conn, &free_entry); ··· 294 291 if (collected > CONNCOUNT_GC_MAX_NODES) 295 292 return false; 296 293 } 297 - return false; 294 + 295 + spin_lock_bh(&list->list_lock); 296 + if (!list->count) { 297 + list->dead = true; 298 + ret = true; 299 + } 300 + spin_unlock_bh(&list->list_lock); 301 + 302 + return ret; 298 303 } 299 304 EXPORT_SYMBOL_GPL(nf_conncount_gc_list); 300 305 ··· 428 417 nf_conncount_list_init(&rbconn->list); 429 418 list_add(&conn->node, &rbconn->list.head); 430 419 count = 1; 420 + rbconn->list.count = count; 431 421 432 422 rb_link_node(&rbconn->node, parent, rbnode); 433 423 rb_insert_color(&rbconn->node, root);