aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-08-29 12:25:49 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-08-31 09:50:28 -0400
commit5b423f6a40a0327f9d40bc8b97ce9be266f74368 (patch)
treef71b7726f6501993bc7be9d4d7e6e69d7cd095b2 /net
parent3f509c689a07a4aa989b426893d8491a7ffcc410 (diff)
netfilter: nf_conntrack: fix racy timer handling with reliable events
Existing code assumes that del_timer returns true for alive conntrack entries. However, this is not true if reliable events are enabled. In that case, del_timer may return true for entries that were just inserted in the dying list. Note that packets / ctnetlink may hold references to conntrack entries that were just inserted to such list. This patch fixes the issue by adding an independent timer for event delivery. This increases the size of the ecache extension. Still we can revisit this later and use variable size extensions to allocate this area on demand. Tested-by: Oliver Smith <olipro@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_conntrack_core.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index cf4875565d67..2ceec64b19f9 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -249,12 +249,15 @@ static void death_by_event(unsigned long ul_conntrack)
249{ 249{
250 struct nf_conn *ct = (void *)ul_conntrack; 250 struct nf_conn *ct = (void *)ul_conntrack;
251 struct net *net = nf_ct_net(ct); 251 struct net *net = nf_ct_net(ct);
252 struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
253
254 BUG_ON(ecache == NULL);
252 255
253 if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { 256 if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
254 /* bad luck, let's retry again */ 257 /* bad luck, let's retry again */
255 ct->timeout.expires = jiffies + 258 ecache->timeout.expires = jiffies +
256 (random32() % net->ct.sysctl_events_retry_timeout); 259 (random32() % net->ct.sysctl_events_retry_timeout);
257 add_timer(&ct->timeout); 260 add_timer(&ecache->timeout);
258 return; 261 return;
259 } 262 }
260 /* we've got the event delivered, now it's dying */ 263 /* we've got the event delivered, now it's dying */
@@ -268,6 +271,9 @@ static void death_by_event(unsigned long ul_conntrack)
268void nf_ct_insert_dying_list(struct nf_conn *ct) 271void nf_ct_insert_dying_list(struct nf_conn *ct)
269{ 272{
270 struct net *net = nf_ct_net(ct); 273 struct net *net = nf_ct_net(ct);
274 struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
275
276 BUG_ON(ecache == NULL);
271 277
272 /* add this conntrack to the dying list */ 278 /* add this conntrack to the dying list */
273 spin_lock_bh(&nf_conntrack_lock); 279 spin_lock_bh(&nf_conntrack_lock);
@@ -275,10 +281,10 @@ void nf_ct_insert_dying_list(struct nf_conn *ct)
275 &net->ct.dying); 281 &net->ct.dying);
276 spin_unlock_bh(&nf_conntrack_lock); 282 spin_unlock_bh(&nf_conntrack_lock);
277 /* set a new timer to retry event delivery */ 283 /* set a new timer to retry event delivery */
278 setup_timer(&ct->timeout, death_by_event, (unsigned long)ct); 284 setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct);
279 ct->timeout.expires = jiffies + 285 ecache->timeout.expires = jiffies +
280 (random32() % net->ct.sysctl_events_retry_timeout); 286 (random32() % net->ct.sysctl_events_retry_timeout);
281 add_timer(&ct->timeout); 287 add_timer(&ecache->timeout);
282} 288}
283EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); 289EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list);
284 290