r2786 - in trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian: . patches patches/series
Simon Horman
horms@costa.debian.org
Tue, 22 Mar 2005 11:51:34 +0100
Author: horms
Date: 2005-03-22 11:51:33 +0100 (Tue, 22 Mar 2005)
New Revision: 2786
Added:
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/148_ip_evictor_smp_loop.diff
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/149_fragment_queue_flush.diff
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-1.diff
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-2.diff
Modified:
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-9
Log:
Fix theoretical loop on SMP in ip_evictor()
Flush fragment queue on conntrack unload.
Keep fragment queues private to each user. See CAN-2005-0449 and
http://oss.sgi.com/archives/netdev/2005-01/msg01048.html
Modified: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog 2005-03-22 10:49:19 UTC (rev 2785)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog 2005-03-22 10:51:33 UTC (rev 2786)
@@ -58,8 +58,21 @@
[SECURITY] Do not leak dst entries in ip_copy_metadata()
See CAN-2005-0210. (Simon Horman)
- -- Simon Horman <horms@debian.org> Tue, 22 Mar 2005 16:46:35 +0900
+ * 148_ip_evitor_smp_loop.diff:
+ Fix theoretical loop on SMP in ip_evictor().
+ (Simon Horman, Andres Salomon)
+ * 149_fragment_queue_flush.diff:
+ Flush fragment queue on conntrack unload. (Simon Horman, Andres Salomon)
+
+ * *** ABI Change! Notify D-I team or delay for future release ***
+ 150_private_fragment_queues-1.diff, 150_private_fragment_queues-2.diff:
+ Keep fragment queues private to each user. See CAN-2005-0449 and
+ http://oss.sgi.com/archives/netdev/2005-01/msg01048.html
+ (Simon Horman, Andres Salomon)
+
+ -- Simon Horman <horms@debian.org> Tue, 22 Mar 2005 18:40:19 +0900
+
kernel-source-2.4.27 (2.4.27-8) unstable; urgency=high
* add dh_fixperms to the build targets to kernel-patch-debian-2.4.27
Added: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/148_ip_evictor_smp_loop.diff
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/148_ip_evictor_smp_loop.diff 2005-03-22 10:49:19 UTC (rev 2785)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/148_ip_evictor_smp_loop.diff 2005-03-22 10:51:33 UTC (rev 2786)
@@ -0,0 +1,165 @@
+# origin: davem (BitKeeper)
+# cset: 1.1449.16.2 (2.4) key=4123c971hKzmQKDWgBjD2OMQ5pd0Jw
+# URL: http://linux.bkbits.net:8080/linux-2.4/cset@4123c971hKzmQKDWgBjD2OMQ5pd0Jw
+# inclusion: upstream
+# descrition: [IPV4]: Fix theoretical loop on SMP in ip_evictor().
+# revision date: Tue, 22 Mar 2005 17:54:23 +0900
+#
+# S rset: ChangeSet|1.1449.16.1..1.1449.16.2
+# I rset: net/ipv4/ip_fragment.c|1.8..1.9
+#
+# Key:
+# S: Skipped ChangeSet file only
+# O: Original Followed by Updated
+# U: Updated Included with updated range of versions
+# I: Included Included verbatim
+# E: Excluded Excluded on request from user
+# D: Deleted Manually deleted by subsequent user edit
+# R: Revised Manually revised by subsequent user edit
+#
+#
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+# 2004/08/18 14:26:09-07:00 davem@nuts.davemloft.net
+# [IPV4]: Fix theoretical loop on SMP in ip_evictor().
+#
+# Snapshot the amount of work to do, and just do it.
+# In this way we avoid a theoretical loop whereby
+# one cpu sits in ip_evictor() tossing fragments
+# while another keeps adding a fragment just as we
+# bring ip_frag_mem down below the low threshold.
+#
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+# net/ipv4/ip_fragment.c
+# 2004/08/18 14:25:49-07:00 davem@nuts.davemloft.net +22 -15
+# [IPV4]: Fix theoretical loop on SMP in ip_evictor().
+#
+# Snapshot the amount of work to do, and just do it.
+# In this way we avoid a theoretical loop whereby
+# one cpu sits in ip_evictor() tossing fragments
+# while another keeps adding a fragment just as we
+# bring ip_frag_mem down below the low threshold.
+#
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+#
+===== net/ipv4/ip_fragment.c 1.8 vs 1.9 =====
+--- 1.8/net/ipv4/ip_fragment.c 2003-05-28 16:49:28 +09:00
++++ 1.9/net/ipv4/ip_fragment.c 2004-08-19 06:25:49 +09:00
+@@ -168,14 +168,18 @@ static void ipfrag_secret_rebuild(unsign
+ atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */
+
+ /* Memory Tracking Functions. */
+-static __inline__ void frag_kfree_skb(struct sk_buff *skb)
++static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work)
+ {
++ if (work)
++ *work -= skb->truesize;
+ atomic_sub(skb->truesize, &ip_frag_mem);
+ kfree_skb(skb);
+ }
+
+-static __inline__ void frag_free_queue(struct ipq *qp)
++static __inline__ void frag_free_queue(struct ipq *qp, int *work)
+ {
++ if (work)
++ *work -= sizeof(struct ipq);
+ atomic_sub(sizeof(struct ipq), &ip_frag_mem);
+ kfree(qp);
+ }
+@@ -194,7 +198,7 @@ static __inline__ struct ipq *frag_alloc
+ /* Destruction primitives. */
+
+ /* Complete destruction of ipq. */
+-static void ip_frag_destroy(struct ipq *qp)
++static void ip_frag_destroy(struct ipq *qp, int *work)
+ {
+ struct sk_buff *fp;
+
+@@ -206,18 +210,18 @@ static void ip_frag_destroy(struct ipq *
+ while (fp) {
+ struct sk_buff *xp = fp->next;
+
+- frag_kfree_skb(fp);
++ frag_kfree_skb(fp, work);
+ fp = xp;
+ }
+
+ /* Finally, release the queue descriptor itself. */
+- frag_free_queue(qp);
++ frag_free_queue(qp, work);
+ }
+
+-static __inline__ void ipq_put(struct ipq *ipq)
++static __inline__ void ipq_put(struct ipq *ipq, int *work)
+ {
+ if (atomic_dec_and_test(&ipq->refcnt))
+- ip_frag_destroy(ipq);
++ ip_frag_destroy(ipq, work);
+ }
+
+ /* Kill ipq entry. It is not destroyed immediately,
+@@ -242,10 +246,13 @@ static void ip_evictor(void)
+ {
+ struct ipq *qp;
+ struct list_head *tmp;
++ int work;
+
+- for(;;) {
+- if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh)
+- return;
++ work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
++ if (work <= 0)
++ return;
++
++ while (work > 0) {
+ read_lock(&ipfrag_lock);
+ if (list_empty(&ipq_lru_list)) {
+ read_unlock(&ipfrag_lock);
+@@ -261,7 +268,7 @@ static void ip_evictor(void)
+ ipq_kill(qp);
+ spin_unlock(&qp->lock);
+
+- ipq_put(qp);
++ ipq_put(qp, &work);
+ IP_INC_STATS_BH(IpReasmFails);
+ }
+ }
+@@ -293,7 +300,7 @@ static void ip_expire(unsigned long arg)
+ }
+ out:
+ spin_unlock(&qp->lock);
+- ipq_put(qp);
++ ipq_put(qp, NULL);
+ }
+
+ /* Creation primitives. */
+@@ -316,7 +323,7 @@ static struct ipq *ip_frag_intern(unsign
+ atomic_inc(&qp->refcnt);
+ write_unlock(&ipfrag_lock);
+ qp_in->last_in |= COMPLETE;
+- ipq_put(qp_in);
++ ipq_put(qp_in, NULL);
+ return qp;
+ }
+ }
+@@ -505,7 +512,7 @@ static void ip_frag_queue(struct ipq *qp
+ qp->fragments = next;
+
+ qp->meat -= free_it->len;
+- frag_kfree_skb(free_it);
++ frag_kfree_skb(free_it, NULL);
+ }
+ }
+
+@@ -656,7 +663,7 @@ struct sk_buff *ip_defrag(struct sk_buff
+ ret = ip_frag_reasm(qp, dev);
+
+ spin_unlock(&qp->lock);
+- ipq_put(qp);
++ ipq_put(qp, NULL);
+ return ret;
+ }
+
Added: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/149_fragment_queue_flush.diff
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/149_fragment_queue_flush.diff 2005-03-22 10:49:19 UTC (rev 2785)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/149_fragment_queue_flush.diff 2005-03-22 10:51:33 UTC (rev 2786)
@@ -0,0 +1,217 @@
+# origin: kaber (BitKeeper)
+# cset: 1.1449.21.26 (2.4) key=4132a90b_ZR2MJK9KLAcYgPV5naI5A
+# URL: http://linux.bkbits.net:8080/linux-2.4/cset@4132a90b_ZR2MJK9KLAcYgPV5naI5A
+# inclusion: upstream
+# descrition: [NETFILTER]: Flush fragment queue on conntrack unload
+# revision date: Tue, 22 Mar 2005 17:55:05 +0900
+#
+# S rset: ChangeSet|1.1449.21.25..1.1449.21.26
+# I rset: net/ipv4/netfilter/ip_conntrack_core.c|1.33..1.34
+# I rset: net/ipv4/ip_fragment.c|1.9..1.10
+# R rset: net/netsyms.c|1.48..1.49
+# I rset: net/ipv4/netfilter/ip_conntrack_standalone.c|1.14..1.15
+# I rset: include/net/ip.h|1.5..1.6
+# I rset: include/linux/netfilter_ipv4/ip_conntrack.h|1.12..1.13
+#
+# Key:
+# S: Skipped ChangeSet file only
+# O: Original Followed by Updated
+# U: Updated Included with updated range of versions
+# I: Included Included verbatim
+# E: Excluded Excluded on request from user
+# D: Deleted Manually deleted by subsequent user edit
+# R: Revised Manually revised by subsequent user edit
+#
+#
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+# 2004/08/29 21:11:55-07:00 kaber@trash.net
+# [NETFILTER]: Flush fragment queue on conntrack unload
+#
+# Problem discovered, and original version of patch, by
+# Olaf Kirch.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+# net/netsyms.c
+# 2004/08/29 21:11:49-07:00 kaber@trash.net +1 -0
+# [NETFILTER]: Flush fragment queue on conntrack unload
+#
+# Problem discovered, and original version of patch, by
+# Olaf Kirch.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+# net/ipv4/netfilter/ip_conntrack_standalone.c
+# 2004/08/29 21:11:49-07:00 kaber@trash.net +7 -0
+# [NETFILTER]: Flush fragment queue on conntrack unload
+#
+# Problem discovered, and original version of patch, by
+# Olaf Kirch.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+# net/ipv4/netfilter/ip_conntrack_core.c
+# 2004/08/29 21:11:49-07:00 kaber@trash.net +8 -0
+# [NETFILTER]: Flush fragment queue on conntrack unload
+#
+# Problem discovered, and original version of patch, by
+# Olaf Kirch.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+# net/ipv4/ip_fragment.c
+# 2004/08/29 21:11:49-07:00 kaber@trash.net +13 -3
+# [NETFILTER]: Flush fragment queue on conntrack unload
+#
+# Problem discovered, and original version of patch, by
+# Olaf Kirch.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+# include/net/ip.h
+# 2004/08/29 21:11:49-07:00 kaber@trash.net +1 -0
+# [NETFILTER]: Flush fragment queue on conntrack unload
+#
+# Problem discovered, and original version of patch, by
+# Olaf Kirch.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+# include/linux/netfilter_ipv4/ip_conntrack.h
+# 2004/08/29 21:11:49-07:00 kaber@trash.net +1 -0
+# [NETFILTER]: Flush fragment queue on conntrack unload
+#
+# Problem discovered, and original version of patch, by
+# Olaf Kirch.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@redhat.com>
+#
+#
+===== net/ipv4/netfilter/ip_conntrack_core.c 1.33 vs 1.34 =====
+--- 1.33/net/ipv4/netfilter/ip_conntrack_core.c 2004-06-22 06:15:33 +09:00
++++ 1.34/net/ipv4/netfilter/ip_conntrack_core.c 2004-08-30 13:11:49 +09:00
+@@ -1183,6 +1183,8 @@ void ip_ct_refresh(struct ip_conntrack *
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ }
+
++int ip_ct_no_defrag;
++
+ /* Returns new sk_buff, or NULL */
+ struct sk_buff *
+ ip_ct_gather_frags(struct sk_buff *skb)
+@@ -1191,6 +1193,12 @@ ip_ct_gather_frags(struct sk_buff *skb)
+ #ifdef CONFIG_NETFILTER_DEBUG
+ unsigned int olddebug = skb->nf_debug;
+ #endif
++
++ if (unlikely(ip_ct_no_defrag)) {
++ kfree_skb(skb);
++ return NULL;
++ }
++
+ if (sk) {
+ sock_hold(sk);
+ skb_orphan(skb);
+===== net/ipv4/ip_fragment.c 1.9 vs 1.10 =====
+--- 1.9/net/ipv4/ip_fragment.c 2004-08-19 06:25:49 +09:00
++++ 1.10/net/ipv4/ip_fragment.c 2004-08-30 13:11:49 +09:00
+@@ -240,15 +240,15 @@ static __inline__ void ipq_kill(struct i
+ }
+
+ /* Memory limiting on fragments. Evictor trashes the oldest
+- * fragment queue until we are back under the low threshold.
++ * fragment queue until we are back under the threshold.
+ */
+-static void ip_evictor(void)
++static void __ip_evictor(int threshold)
+ {
+ struct ipq *qp;
+ struct list_head *tmp;
+ int work;
+
+- work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
++ work = atomic_read(&ip_frag_mem) - threshold;
+ if (work <= 0)
+ return;
+
+@@ -273,6 +273,11 @@ static void ip_evictor(void)
+ }
+ }
+
++static inline void ip_evictor(void)
++{
++ __ip_evictor(sysctl_ipfrag_low_thresh);
++}
++
+ /*
+ * Oops, a fragment queue timed out. Kill it and send an ICMP reply.
+ */
+@@ -681,4 +686,9 @@ void ipfrag_init(void)
+ ipfrag_secret_timer.function = ipfrag_secret_rebuild;
+ ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
+ add_timer(&ipfrag_secret_timer);
++}
++
++void ipfrag_flush(void)
++{
++ __ip_evictor(0);
+ }
+===== net/netsyms.c 1.48 vs 1.49.edit =====
+--- 1.48/net/netsyms.c 2004-06-09 03:27:18 +09:00
++++ 1.49.edit/net/netsyms.c 2005-03-22 19:07:37.591410712 +0900
+@@ -290,6 +290,7 @@ EXPORT_SYMBOL(ip_dev_find);
+ EXPORT_SYMBOL(inetdev_by_index);
+ EXPORT_SYMBOL(in_dev_finish_destroy);
+ EXPORT_SYMBOL(ip_defrag);
++EXPORT_SYMBOL(ipfrag_flush);
+ EXPORT_SYMBOL(inet_peer_idlock);
+
+ /* Route manipulation */
+===== net/ipv4/netfilter/ip_conntrack_standalone.c 1.14 vs 1.15 =====
+--- 1.14/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-06-22 06:16:57 +09:00
++++ 1.15/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-08-30 13:11:49 +09:00
+@@ -393,6 +393,13 @@ static int init_or_cleanup(int init)
+ cleanup_inandlocalops:
+ nf_unregister_hook(&ip_conntrack_local_out_ops);
+ cleanup_inops:
++ /* Frag queues may hold fragments with skb->dst == NULL */
++ ip_ct_no_defrag = 1;
++ local_bh_disable();
++ br_write_lock(BR_NETPROTO_LOCK);
++ br_write_unlock(BR_NETPROTO_LOCK);
++ ipfrag_flush();
++ local_bh_enable();
+ nf_unregister_hook(&ip_conntrack_in_ops);
+ cleanup_proc:
+ proc_net_remove("ip_conntrack");
+===== include/net/ip.h 1.5 vs 1.6 =====
+--- 1.5/include/net/ip.h 2004-08-16 11:28:55 +09:00
++++ 1.6/include/net/ip.h 2004-08-30 13:11:49 +09:00
+@@ -228,6 +228,7 @@ extern int ip_call_ra_chain(struct sk_bu
+ */
+
+ struct sk_buff *ip_defrag(struct sk_buff *skb);
++extern void ipfrag_flush(void);
+ extern int ip_frag_nqueues;
+ extern atomic_t ip_frag_mem;
+
+===== include/linux/netfilter_ipv4/ip_conntrack.h 1.12 vs 1.13 =====
+--- 1.12/include/linux/netfilter_ipv4/ip_conntrack.h 2004-06-22 06:15:33 +09:00
++++ 1.13/include/linux/netfilter_ipv4/ip_conntrack.h 2004-08-30 13:11:49 +09:00
+@@ -249,6 +249,7 @@ extern void ip_ct_refresh(struct ip_conn
+ /* Call me when a conntrack is destroyed. */
+ extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
+
++extern int ip_ct_no_defrag;
+ /* Returns new sk_buff, or NULL */
+ struct sk_buff *
+ ip_ct_gather_frags(struct sk_buff *skb);
Added: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-1.diff
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-1.diff 2005-03-22 10:49:19 UTC (rev 2785)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-1.diff 2005-03-22 10:51:33 UTC (rev 2786)
@@ -0,0 +1,402 @@
+# origin: kaber (BitKeeper)
+# cset: 1.1521.1.59 (2.4) key=41f88485GhpPWpvjU0X_-6IkvMcbRA
+# URL: http://linux.bkbits.net:8080/linux-2.4/cset@41f88485GhpPWpvjU0X_-6IkvMcbRA
+# inclusion: upstream
+# descrition: [IPV4]: Keep fragment queues private to each user.
+# revision date: Tue, 22 Mar 2005 17:55:17 +0900
+#
+# S rset: ChangeSet|1.1521.1.58..1.1521.1.59
+# I rset: net/ipv4/netfilter/ip_conntrack_core.c|1.35..1.36
+# I rset: net/ipv4/ip_input.c|1.6..1.7
+# I rset: net/ipv4/ipvs/ip_vs_core.c|1.2..1.3
+# I rset: net/ipv4/ip_fragment.c|1.10..1.11
+# R rset: net/netsyms.c|1.52..1.53
+# I rset: net/ipv4/netfilter/ip_conntrack_standalone.c|1.16..1.17
+# I rset: include/net/ip.h|1.7..1.8
+# I rset: net/ipv4/netfilter/ip_nat_standalone.c|1.21..1.22
+# I rset: include/linux/netfilter_ipv4/ip_conntrack.h|1.13..1.14
+#
+# Key:
+# S: Skipped ChangeSet file only
+# O: Original Followed by Updated
+# U: Updated Included with updated range of versions
+# I: Included Included verbatim
+# E: Excluded Excluded on request from user
+# D: Deleted Manually deleted by subsequent user edit
+# R: Revised Manually revised by subsequent user edit
+#
+#
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+# 2005/01/26 22:04:53-08:00 kaber@trash.net
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# net/netsyms.c
+# 2005/01/26 22:04:48-08:00 kaber@trash.net +0 -1
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# net/ipv4/netfilter/ip_nat_standalone.c
+# 2005/01/26 22:04:48-08:00 kaber@trash.net +1 -1
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# net/ipv4/netfilter/ip_conntrack_standalone.c
+# 2005/01/26 22:04:48-08:00 kaber@trash.net +0 -7
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# net/ipv4/netfilter/ip_conntrack_core.c
+# 2005/01/26 22:04:47-08:00 kaber@trash.net +6 -10
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# net/ipv4/ipvs/ip_vs_core.c
+# 2005/01/26 22:04:47-08:00 kaber@trash.net +3 -3
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# net/ipv4/ip_input.c
+# 2005/01/26 22:04:47-08:00 kaber@trash.net +2 -2
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# net/ipv4/ip_fragment.c
+# 2005/01/26 22:04:47-08:00 kaber@trash.net +13 -19
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# include/net/ip.h
+# 2005/01/26 22:04:47-08:00 kaber@trash.net +13 -3
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+# include/linux/netfilter_ipv4/ip_conntrack.h
+# 2005/01/26 22:04:47-08:00 kaber@trash.net +1 -2
+# [IPV4]: Keep fragment queues private to each user.
+#
+# Signed-off-by: Patrick McHardy <kaber@trash.net>
+# Signed-off-by: David S. Miller <davem@davemloft.net>
+#
+#
+===== net/ipv4/netfilter/ip_conntrack_core.c 1.35 vs 1.36 =====
+--- 1.35/net/ipv4/netfilter/ip_conntrack_core.c 2004-12-22 01:24:54 +09:00
++++ 1.36/net/ipv4/netfilter/ip_conntrack_core.c 2005-01-27 15:04:47 +09:00
+@@ -834,7 +834,10 @@ unsigned int ip_conntrack_in(unsigned in
+
+ /* Gather fragments. */
+ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+- *pskb = ip_ct_gather_frags(*pskb);
++ *pskb = ip_ct_gather_frags(*pskb,
++ hooknum == NF_IP_PRE_ROUTING ?
++ IP_DEFRAG_CONNTRACK_IN :
++ IP_DEFRAG_CONNTRACK_OUT);
+ if (!*pskb)
+ return NF_STOLEN;
+ }
+@@ -1183,29 +1186,22 @@ void ip_ct_refresh(struct ip_conntrack *
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ }
+
+-int ip_ct_no_defrag;
+-
+ /* Returns new sk_buff, or NULL */
+ struct sk_buff *
+-ip_ct_gather_frags(struct sk_buff *skb)
++ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user)
+ {
+ struct sock *sk = skb->sk;
+ #ifdef CONFIG_NETFILTER_DEBUG
+ unsigned int olddebug = skb->nf_debug;
+ #endif
+
+- if (unlikely(ip_ct_no_defrag)) {
+- kfree_skb(skb);
+- return NULL;
+- }
+-
+ if (sk) {
+ sock_hold(sk);
+ skb_orphan(skb);
+ }
+
+ local_bh_disable();
+- skb = ip_defrag(skb);
++ skb = ip_defrag(skb, user);
+ local_bh_enable();
+
+ if (!skb) {
+===== net/ipv4/ip_input.c 1.6 vs 1.7 =====
+--- 1.6/net/ipv4/ip_input.c 2004-06-22 06:21:17 +09:00
++++ 1.7/net/ipv4/ip_input.c 2005-01-27 15:04:47 +09:00
+@@ -170,7 +170,7 @@ int ip_call_ra_chain(struct sk_buff *skb
+ && ((sk->bound_dev_if == 0)
+ || (sk->bound_dev_if == skb->dev->ifindex))) {
+ if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+- skb = ip_defrag(skb);
++ skb = ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN);
+ if (skb == NULL) {
+ read_unlock(&ip_ra_lock);
+ return 1;
+@@ -291,7 +291,7 @@ int ip_local_deliver(struct sk_buff *skb
+ */
+
+ if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+- skb = ip_defrag(skb);
++ skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER);
+ if (!skb)
+ return 0;
+ }
+===== net/ipv4/ipvs/ip_vs_core.c 1.2 vs 1.3 =====
+--- 1.2/net/ipv4/ipvs/ip_vs_core.c 2005-01-11 05:19:08 +09:00
++++ 1.3/net/ipv4/ipvs/ip_vs_core.c 2005-01-27 15:04:47 +09:00
+@@ -506,7 +506,7 @@ static int ip_vs_out_icmp(struct sk_buff
+
+ /* reassemble IP fragments, but will it happen in ICMP packets?? */
+ if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+- skb = ip_defrag(skb);
++ skb = ip_defrag(skb, IP_DEFRAG_VS_OUT);
+ if (!skb)
+ return NF_STOLEN;
+ *skb_p = skb;
+@@ -658,7 +658,7 @@ static unsigned int ip_vs_out(unsigned i
+
+ /* reassemble IP fragments */
+ if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+- skb = ip_defrag(skb);
++ skb = ip_defrag(skb, IP_DEFRAG_VS_OUT);
+ if (!skb)
+ return NF_STOLEN;
+ iph = skb->nh.iph;
+@@ -1164,7 +1164,7 @@ static unsigned int ip_vs_forward_icmp(u
+ return NF_ACCEPT;
+
+ if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+- skb = ip_defrag(skb);
++ skb = ip_defrag(skb, IP_DEFRAG_VS_FWD);
+ if (!skb)
+ return NF_STOLEN;
+ *skb_p = skb;
+===== net/ipv4/ip_fragment.c 1.10 vs 1.11 =====
+--- 1.10/net/ipv4/ip_fragment.c 2004-08-30 13:11:49 +09:00
++++ 1.11/net/ipv4/ip_fragment.c 2005-01-27 15:04:47 +09:00
+@@ -72,6 +72,7 @@ struct ipfrag_skb_cb
+ struct ipq {
+ struct ipq *next; /* linked list pointers */
+ struct list_head lru_list; /* lru list member */
++ u32 user;
+ u32 saddr;
+ u32 daddr;
+ u16 id;
+@@ -242,13 +243,13 @@ static __inline__ void ipq_kill(struct i
+ /* Memory limiting on fragments. Evictor trashes the oldest
+ * fragment queue until we are back under the threshold.
+ */
+-static void __ip_evictor(int threshold)
++static void ip_evictor(void)
+ {
+ struct ipq *qp;
+ struct list_head *tmp;
+ int work;
+
+- work = atomic_read(&ip_frag_mem) - threshold;
++ work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
+ if (work <= 0)
+ return;
+
+@@ -273,11 +274,6 @@ static void __ip_evictor(int threshold)
+ }
+ }
+
+-static inline void ip_evictor(void)
+-{
+- __ip_evictor(sysctl_ipfrag_low_thresh);
+-}
+-
+ /*
+ * Oops, a fragment queue timed out. Kill it and send an ICMP reply.
+ */
+@@ -324,7 +320,8 @@ static struct ipq *ip_frag_intern(unsign
+ if(qp->id == qp_in->id &&
+ qp->saddr == qp_in->saddr &&
+ qp->daddr == qp_in->daddr &&
+- qp->protocol == qp_in->protocol) {
++ qp->protocol == qp_in->protocol &&
++ qp->user == qp_in->user) {
+ atomic_inc(&qp->refcnt);
+ write_unlock(&ipfrag_lock);
+ qp_in->last_in |= COMPLETE;
+@@ -351,7 +348,7 @@ static struct ipq *ip_frag_intern(unsign
+ }
+
+ /* Add an entry to the 'ipq' queue for a newly received IP datagram. */
+-static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph)
++static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user)
+ {
+ struct ipq *qp;
+
+@@ -363,6 +360,7 @@ static struct ipq *ip_frag_create(unsign
+ qp->id = iph->id;
+ qp->saddr = iph->saddr;
+ qp->daddr = iph->daddr;
++ qp->user = user;
+ qp->len = 0;
+ qp->meat = 0;
+ qp->fragments = NULL;
+@@ -385,7 +383,7 @@ out_nomem:
+ /* Find the correct entry in the "incomplete datagrams" queue for
+ * this IP datagram, and create new one, if nothing is found.
+ */
+-static inline struct ipq *ip_find(struct iphdr *iph)
++static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
+ {
+ __u16 id = iph->id;
+ __u32 saddr = iph->saddr;
+@@ -399,7 +397,8 @@ static inline struct ipq *ip_find(struct
+ if(qp->id == id &&
+ qp->saddr == saddr &&
+ qp->daddr == daddr &&
+- qp->protocol == protocol) {
++ qp->protocol == protocol &&
++ qp->user == user) {
+ atomic_inc(&qp->refcnt);
+ read_unlock(&ipfrag_lock);
+ return qp;
+@@ -407,7 +406,7 @@ static inline struct ipq *ip_find(struct
+ }
+ read_unlock(&ipfrag_lock);
+
+- return ip_frag_create(hash, iph);
++ return ip_frag_create(hash, iph, user);
+ }
+
+ /* Add new segment to existing queue. */
+@@ -641,7 +640,7 @@ out_fail:
+ }
+
+ /* Process an incoming IP datagram fragment. */
+-struct sk_buff *ip_defrag(struct sk_buff *skb)
++struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
+ {
+ struct iphdr *iph = skb->nh.iph;
+ struct ipq *qp;
+@@ -656,7 +655,7 @@ struct sk_buff *ip_defrag(struct sk_buff
+ dev = skb->dev;
+
+ /* Lookup (or create) queue header */
+- if ((qp = ip_find(iph)) != NULL) {
++ if ((qp = ip_find(iph, user)) != NULL) {
+ struct sk_buff *ret = NULL;
+
+ spin_lock(&qp->lock);
+@@ -686,9 +685,4 @@ void ipfrag_init(void)
+ ipfrag_secret_timer.function = ipfrag_secret_rebuild;
+ ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
+ add_timer(&ipfrag_secret_timer);
+-}
+-
+-void ipfrag_flush(void)
+-{
+- __ip_evictor(0);
+ }
+===== net/netsyms.c 1.52 vs 1.53 =====
+--- 1.52/net/netsyms.c 2004-12-22 01:18:12 +09:00
++++ 1.53/net/netsyms.c 2005-03-22 19:39:20.354223224 +0900
+@@ -290,7 +290,6 @@ EXPORT_SYMBOL(ip_dev_find);
+ EXPORT_SYMBOL(inetdev_by_index);
+ EXPORT_SYMBOL(in_dev_finish_destroy);
+ EXPORT_SYMBOL(ip_defrag);
+-EXPORT_SYMBOL(ipfrag_flush);
+ EXPORT_SYMBOL(inet_peer_idlock);
+
+ /* Route manipulation */
+===== net/ipv4/netfilter/ip_conntrack_standalone.c 1.16 vs 1.17 =====
+--- 1.16/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-12-22 01:24:54 +09:00
++++ 1.17/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-01-27 15:04:48 +09:00
+@@ -393,13 +393,6 @@ static int init_or_cleanup(int init)
+ cleanup_inandlocalops:
+ nf_unregister_hook(&ip_conntrack_local_out_ops);
+ cleanup_inops:
+- /* Frag queues may hold fragments with skb->dst == NULL */
+- ip_ct_no_defrag = 1;
+- local_bh_disable();
+- br_write_lock(BR_NETPROTO_LOCK);
+- br_write_unlock(BR_NETPROTO_LOCK);
+- ipfrag_flush();
+- local_bh_enable();
+ nf_unregister_hook(&ip_conntrack_in_ops);
+ cleanup_proc:
+ proc_net_remove("ip_conntrack");
+===== include/net/ip.h 1.7 vs 1.8 =====
+--- 1.7/include/net/ip.h 2004-12-22 01:18:12 +09:00
++++ 1.8/include/net/ip.h 2005-01-27 15:04:47 +09:00
+@@ -227,9 +227,19 @@ extern int ip_call_ra_chain(struct sk_bu
+ /*
+ * Functions provided by ip_fragment.o
+ */
+-
+-struct sk_buff *ip_defrag(struct sk_buff *skb);
+-extern void ipfrag_flush(void);
++
++enum ip_defrag_users
++{
++ IP_DEFRAG_LOCAL_DELIVER,
++ IP_DEFRAG_CALL_RA_CHAIN,
++ IP_DEFRAG_CONNTRACK_IN,
++ IP_DEFRAG_CONNTRACK_OUT,
++ IP_DEFRAG_NAT_OUT,
++ IP_DEFRAG_VS_OUT,
++ IP_DEFRAG_VS_FWD
++};
++
++struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user);
+ extern int ip_frag_nqueues;
+ extern atomic_t ip_frag_mem;
+
+===== net/ipv4/netfilter/ip_nat_standalone.c 1.21 vs 1.22 =====
+--- 1.21/net/ipv4/netfilter/ip_nat_standalone.c 2004-12-22 01:26:09 +09:00
++++ 1.22/net/ipv4/netfilter/ip_nat_standalone.c 2005-01-27 15:04:48 +09:00
+@@ -201,7 +201,7 @@ ip_nat_out(unsigned int hooknum,
+ I'm starting to have nightmares about fragments. */
+
+ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+- *pskb = ip_ct_gather_frags(*pskb);
++ *pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_NAT_OUT);
+
+ if (!*pskb)
+ return NF_STOLEN;
+===== include/linux/netfilter_ipv4/ip_conntrack.h 1.13 vs 1.14 =====
+--- 1.13/include/linux/netfilter_ipv4/ip_conntrack.h 2004-08-30 13:11:49 +09:00
++++ 1.14/include/linux/netfilter_ipv4/ip_conntrack.h 2005-01-27 15:04:47 +09:00
+@@ -249,10 +249,9 @@ extern void ip_ct_refresh(struct ip_conn
+ /* Call me when a conntrack is destroyed. */
+ extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
+
+-extern int ip_ct_no_defrag;
+ /* Returns new sk_buff, or NULL */
+ struct sk_buff *
+-ip_ct_gather_frags(struct sk_buff *skb);
++ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user);
+
+ /* Delete all conntracks which match. */
+ extern void
Added: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-2.diff
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-2.diff 2005-03-22 10:49:19 UTC (rev 2785)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/150_private_fragment_queues-2.diff 2005-03-22 10:51:33 UTC (rev 2786)
@@ -0,0 +1,16 @@
+# origin: Horms <horms@debian.org>
+# description: fix for ipfras queue's for ip_fw_compat.c
+# inclusion: This code does not seem to be upstream any more
+# revision date: 2005-02-23
+--- a/net/ipv4/netfilter/ip_fw_compat.c.unedited 2005-02-23 11:56:51.000000000 +0900
++++ b/net/ipv4/netfilter/ip_fw_compat.c 2005-02-23 11:56:53.000000000 +0900
+@@ -80,7 +80,8 @@ fw_in(unsigned int hooknum,
+ &redirpt, pskb);
+
+ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+- *pskb = ip_ct_gather_frags(*pskb);
++ *pskb = ip_ct_gather_frags(*pskb,
++ IP_DEFRAG_CONNTRACK_IN);
+
+ if (!*pskb)
+ return NF_STOLEN;
Modified: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-9
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-9 2005-03-22 10:49:19 UTC (rev 2785)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-9 2005-03-22 10:51:33 UTC (rev 2786)
@@ -13,3 +13,7 @@
+ 145_insert_vm_struct-no-BUG.diff
+ 146_ip6_copy_metadata_leak.diff
+ 147_ip_copy_metadata_leak.diff
++ 148_ip_evictor_smp_loop.diff
++ 149_fragment_queue_flush.diff
++ 150_private_fragment_queues-1.diff
++ 150_private_fragment_queues-2.diff