aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2005-08-09 23:02:13 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 18:38:54 -0400
commita86888b925299330053d20e0eba03ac4d2648c4b (patch)
tree27c2d22d98a9eed22749df1a8d32f72e1b5a2468 /include
parenta55ebcc4c4532107ad9eee1c9bb698ab5f12c00f (diff)
[NETFILTER]: Fix multiple problems with the conntrack event cache
refcnt underflow: the reference count is decremented when a conntrack entry is removed from the hash but it is not incremented when entering new entries. missing protection of process context against softirq context: all cache operations need to locally disable softirqs to avoid races. Additionally the event cache can't be initialized when a packet enteres the conntrack code but needs to be initialized whenever we cache an event and the stored conntrack entry doesn't match the current one. incorrect flushing of the event cache in ip_ct_iterate_cleanup: without real locking we can't flush the cache for different CPUs without incurring races. The cache for different CPUs can only be flushed when no packets are going through the code. ip_ct_iterate_cleanup doesn't need to drop all references, so flushing is moved to the cleanup path. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack.h29
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_core.h14
2 files changed, 18 insertions, 25 deletions
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index ff2c1c6001f9..088742befe49 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -411,6 +411,7 @@ struct ip_conntrack_stat
411 411
412#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS 412#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
413#include <linux/notifier.h> 413#include <linux/notifier.h>
414#include <linux/interrupt.h>
414 415
415struct ip_conntrack_ecache { 416struct ip_conntrack_ecache {
416 struct ip_conntrack *ct; 417 struct ip_conntrack *ct;
@@ -445,26 +446,24 @@ ip_conntrack_expect_unregister_notifier(struct notifier_block *nb)
445 return notifier_chain_unregister(&ip_conntrack_expect_chain, nb); 446 return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
446} 447}
447 448
449extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct);
450extern void __ip_ct_event_cache_init(struct ip_conntrack *ct);
451
448static inline void 452static inline void
449ip_conntrack_event_cache(enum ip_conntrack_events event, 453ip_conntrack_event_cache(enum ip_conntrack_events event,
450 const struct sk_buff *skb) 454 const struct sk_buff *skb)
451{ 455{
452 struct ip_conntrack_ecache *ecache = 456 struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct;
453 &__get_cpu_var(ip_conntrack_ecache); 457 struct ip_conntrack_ecache *ecache;
454 458
455 if (unlikely((struct ip_conntrack *) skb->nfct != ecache->ct)) { 459 local_bh_disable();
456 if (net_ratelimit()) { 460 ecache = &__get_cpu_var(ip_conntrack_ecache);
457 printk(KERN_ERR "ctevent: skb->ct != ecache->ct !!!\n"); 461 if (ct != ecache->ct)
458 dump_stack(); 462 __ip_ct_event_cache_init(ct);
459 }
460 }
461 ecache->events |= event; 463 ecache->events |= event;
464 local_bh_enable();
462} 465}
463 466
464extern void
465ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct);
466extern void ip_conntrack_event_cache_init(const struct sk_buff *skb);
467
468static inline void ip_conntrack_event(enum ip_conntrack_events event, 467static inline void ip_conntrack_event(enum ip_conntrack_events event,
469 struct ip_conntrack *ct) 468 struct ip_conntrack *ct)
470{ 469{
@@ -483,9 +482,7 @@ static inline void ip_conntrack_event_cache(enum ip_conntrack_events event,
483 const struct sk_buff *skb) {} 482 const struct sk_buff *skb) {}
484static inline void ip_conntrack_event(enum ip_conntrack_events event, 483static inline void ip_conntrack_event(enum ip_conntrack_events event,
485 struct ip_conntrack *ct) {} 484 struct ip_conntrack *ct) {}
486static inline void ip_conntrack_deliver_cached_events_for( 485static inline void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) {}
487 struct ip_conntrack *ct) {}
488static inline void ip_conntrack_event_cache_init(const struct sk_buff *skb) {}
489static inline void 486static inline void
490ip_conntrack_expect_event(enum ip_conntrack_expect_events event, 487ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
491 struct ip_conntrack_expect *exp) {} 488 struct ip_conntrack_expect *exp) {}
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
index fbf6c3e41647..dc4d2a0575de 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h
@@ -44,18 +44,14 @@ static inline int ip_conntrack_confirm(struct sk_buff **pskb)
44 struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct; 44 struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
45 int ret = NF_ACCEPT; 45 int ret = NF_ACCEPT;
46 46
47 if (ct && !is_confirmed(ct)) 47 if (ct) {
48 ret = __ip_conntrack_confirm(pskb); 48 if (!is_confirmed(ct))
49 ip_conntrack_deliver_cached_events_for(ct); 49 ret = __ip_conntrack_confirm(pskb);
50 50 ip_ct_deliver_cached_events(ct);
51 }
51 return ret; 52 return ret;
52} 53}
53 54
54#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
55struct ip_conntrack_ecache;
56extern void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ec);
57#endif
58
59extern void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp); 55extern void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp);
60 56
61extern struct list_head *ip_conntrack_hash; 57extern struct list_head *ip_conntrack_hash;