Re: [OOPS] on linux 2.6 while using IPSec.

From: Herbert Xu (herbert@gondor.apana.org.au)
Date: Fri Jul 25 2003 - 23:11:20 EST


Ranjeet Shetye <ranjeet.shetye2@zultys.com> wrote:
>
> kernel is 2.6.0-test1 from bk (current as of Fri, July 25), talking to
> a 2.4.21 kernel with IPSec backport. IPSec is tunnel mode, ESP and AH
> with AES and MD5 for phase 1 and phase 2. PFS is off. default
> lifetimes. no modules loaded on 2.6 kernel.
>
> Starting tetheral (intf going into promiscuous mode ?) triggers this
> bug consistently.

When an secpath is COWed, we lose reference to the states.

Does this patch help?

-- 
Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ )
Email:  Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
Index: kernel-source-2.5/include/net/xfrm.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/xfrm.h,v
retrieving revision 1.14
diff -u -r1.14 xfrm.h
--- kernel-source-2.5/include/net/xfrm.h	26 Jul 2003 03:56:01 -0000	1.14
+++ kernel-source-2.5/include/net/xfrm.h	26 Jul 2003 04:06:29 -0000
@@ -9,7 +9,6 @@
 #include <linux/crypto.h>
 #include <linux/pfkeyv2.h>
 #include <linux/in6.h>
-#include <linux/slab.h>
 
 #include <net/sock.h>
 #include <net/dst.h>
@@ -539,7 +538,6 @@
 
 struct sec_path
 {
-	kmem_cache_t		*pool;
 	atomic_t		refcnt;
 	int			len;
 	struct sec_decap_state	x[XFRM_MAX_DEPTH];
@@ -562,6 +560,8 @@
 		__secpath_destroy(sp);
 }
 
+extern struct sec_path *secpath_dup(struct sec_path *src);
+
 static inline int
 __xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x)
 {
@@ -818,8 +818,7 @@
 extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
 extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard);
 
-extern void xfrm4_input_init(void);
-extern void xfrm6_input_init(void);
+extern void xfrm_input_init(void);
 extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq);
 
 extern void xfrm_probe_algs(void);
Index: kernel-source-2.5/net/ipv4/xfrm4_input.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/xfrm4_input.c,v
retrieving revision 1.3
diff -u -r1.3 xfrm4_input.c
--- kernel-source-2.5/net/ipv4/xfrm4_input.c	26 Jul 2003 03:56:01 -0000	1.3
+++ kernel-source-2.5/net/ipv4/xfrm4_input.c	26 Jul 2003 03:48:44 -0000
@@ -9,13 +9,10 @@
  * 	
  */
 
-#include <linux/slab.h>
 #include <net/inet_ecn.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 
-static kmem_cache_t *secpath_cachep;
-
 int xfrm4_rcv(struct sk_buff *skb)
 {
 	return xfrm4_rcv_encap(skb, 0);
@@ -100,19 +97,12 @@
 	/* Allocate new secpath or COW existing one. */
 
 	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
-		kmem_cache_t *pool = skb->sp ? skb->sp->pool : secpath_cachep;
 		struct sec_path *sp;
-		sp = kmem_cache_alloc(pool, SLAB_ATOMIC);
+		sp = secpath_dup(skb->sp);
 		if (!sp)
 			goto drop;
-		if (skb->sp) {
-			memcpy(sp, skb->sp, sizeof(struct sec_path));
+		if (skb->sp)
 			secpath_put(skb->sp);
-		} else {
-			sp->pool = pool;
-			sp->len = 0;
-		}
-		atomic_set(&sp->refcnt, 1);
 		skb->sp = sp;
 	}
 	if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
@@ -142,16 +132,3 @@
 	kfree_skb(skb);
 	return 0;
 }
-
-
-void __init xfrm4_input_init(void)
-{
-	secpath_cachep = kmem_cache_create("secpath4_cache",
-					   sizeof(struct sec_path),
-					   0, SLAB_HWCACHE_ALIGN,
-					   NULL, NULL);
-
-	if (!secpath_cachep)
-		panic("IP: failed to allocate secpath4_cache\n");
-}
-
Index: kernel-source-2.5/net/ipv4/xfrm4_policy.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/xfrm4_policy.c,v
retrieving revision 1.2
diff -u -r1.2 xfrm4_policy.c
--- kernel-source-2.5/net/ipv4/xfrm4_policy.c	13 Jun 2003 11:23:45 -0000	1.2
+++ kernel-source-2.5/net/ipv4/xfrm4_policy.c	26 Jul 2003 04:06:46 -0000
@@ -271,7 +271,6 @@
 {
 	xfrm4_state_init();
 	xfrm4_policy_init();
-	xfrm4_input_init();
 }
 
 void __exit xfrm4_fini(void)
Index: kernel-source-2.5/net/ipv6/xfrm6_input.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/xfrm6_input.c,v
retrieving revision 1.2
diff -u -r1.2 xfrm6_input.c
--- kernel-source-2.5/net/ipv6/xfrm6_input.c	26 Jul 2003 03:56:02 -0000	1.2
+++ kernel-source-2.5/net/ipv6/xfrm6_input.c	26 Jul 2003 03:52:04 -0000
@@ -14,8 +14,6 @@
 #include <net/ipv6.h>
 #include <net/xfrm.h>
 
-static kmem_cache_t *secpath_cachep;
-
 static inline void ipip6_ecn_decapsulate(struct ipv6hdr *iph,
 					 struct sk_buff *skb)
 {
@@ -93,19 +91,12 @@
 
 	/* Allocate new secpath or COW existing one. */
 	if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
-		kmem_cache_t *pool = skb->sp ? skb->sp->pool : secpath_cachep;
 		struct sec_path *sp;
-		sp = kmem_cache_alloc(pool, SLAB_ATOMIC);
+		sp = secpath_dup(skb->sp);
 		if (!sp)
 			goto drop;
-		if (skb->sp) {
-			memcpy(sp, skb->sp, sizeof(struct sec_path));
+		if (skb->sp)
 			secpath_put(skb->sp);
-		} else {
-			sp->pool = pool;
-			sp->len = 0;
-		}
-		atomic_set(&sp->refcnt, 1);
 		skb->sp = sp;
 	}
 
@@ -136,15 +127,3 @@
 	kfree_skb(skb);
 	return -1;
 }
-
-void __init xfrm6_input_init(void)
-{
-	secpath_cachep = kmem_cache_create("secpath6_cache",
-					   sizeof(struct sec_path),
-					   0, SLAB_HWCACHE_ALIGN,
-					   NULL, NULL);
-
-	if (!secpath_cachep)
-		panic("IPv6: failed to allocate secpath6_cache\n");
-}
-
Index: kernel-source-2.5/net/ipv6/xfrm6_policy.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/xfrm6_policy.c,v
retrieving revision 1.4
diff -u -r1.4 xfrm6_policy.c
--- kernel-source-2.5/net/ipv6/xfrm6_policy.c	9 Jul 2003 09:18:42 -0000	1.4
+++ kernel-source-2.5/net/ipv6/xfrm6_policy.c	26 Jul 2003 04:06:55 -0000
@@ -274,7 +274,6 @@
 {
 	xfrm6_policy_init();
 	xfrm6_state_init();
-	xfrm6_input_init();
 }
 
 void __exit xfrm6_fini(void)
Index: kernel-source-2.5/net/xfrm/xfrm_input.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/xfrm/xfrm_input.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 xfrm_input.c
--- kernel-source-2.5/net/xfrm/xfrm_input.c	2 Jul 2003 20:40:16 -0000	1.1.1.3
+++ kernel-source-2.5/net/xfrm/xfrm_input.c	26 Jul 2003 03:45:57 -0000
@@ -7,15 +7,38 @@
  * 	
  */
 
+#include <linux/slab.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 
+static kmem_cache_t *secpath_cachep;
+
 void __secpath_destroy(struct sec_path *sp)
 {
 	int i;
 	for (i = 0; i < sp->len; i++)
 		xfrm_state_put(sp->x[i].xvec);
-	kmem_cache_free(sp->pool, sp);
+	kmem_cache_free(secpath_cachep, sp);
+}
+
+struct sec_path *secpath_dup(struct sec_path *src)
+{
+	struct sec_path *sp;
+
+	sp = kmem_cache_alloc(secpath_cachep, SLAB_ATOMIC);
+	if (!sp)
+		return NULL;
+
+	sp->len = 0;
+	if (src) {
+		int i;
+
+		memcpy(sp, src, sizeof(*sp));
+		for (i = 0; i < sp->len; i++)
+			xfrm_state_hold(sp->x[i].xvec);
+	}
+	atomic_set(&sp->refcnt, 1);
+	return sp;
 }
 
 /* Fetch spi and seq from ipsec header */
@@ -49,4 +72,14 @@
 	*spi = *(u32*)(skb->h.raw + offset);
 	*seq = *(u32*)(skb->h.raw + offset_seq);
 	return 0;
+}
+
+void __init xfrm_input_init(void)
+{
+	secpath_cachep = kmem_cache_create("secpath_cache",
+					   sizeof(struct sec_path),
+					   0, SLAB_HWCACHE_ALIGN,
+					   NULL, NULL);
+	if (!secpath_cachep)
+		panic("XFRM: failed to allocate secpath_cache\n");
 }
Index: kernel-source-2.5/net/xfrm/xfrm_policy.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/xfrm/xfrm_policy.c,v
retrieving revision 1.22
diff -u -r1.22 xfrm_policy.c
--- kernel-source-2.5/net/xfrm/xfrm_policy.c	14 Jul 2003 10:07:57 -0000	1.22
+++ kernel-source-2.5/net/xfrm/xfrm_policy.c	26 Jul 2003 04:07:02 -0000
@@ -1223,5 +1223,6 @@
 {
 	xfrm_state_init();
 	xfrm_policy_init();
+	xfrm_input_init();
 }
 
-
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



This archive was generated by hypermail 2b29 : Thu Jul 31 2003 - 22:00:01 EST