netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [IPSEC] fix ref counting in __xfrm4_bundle_create()
@ 2004-05-29  0:14 Eugene Surovegin
  2004-05-29  3:27 ` Herbert Xu
  0 siblings, 1 reply; 5+ messages in thread
From: Eugene Surovegin @ 2004-05-29  0:14 UTC (permalink / raw)
  To: netdev

Hi all!

I think there is a ref counting bug in error path of __xfrm4_bundle_create().

xfrm_lookup() assumes that xfrm_bundle_create() will take ownership of 
xfrm_state array passed to it. If xfrm_bundle_create() fails, xfrm_lookup() will 
call xfrm_state_put() to release this array. 

Unfortunately, error path in __xfrm4_bundle_create() also calls xfrm_state_put() 
(indirectly through dst_free() -> ... -> xfrm_dst_destroy()) and we end up 
calling xfrm_state_put() _twice_.

This causes "infamous" :) "x->km.state == XFRM_STATE_DEAD" assertion in some our 
tests when interface is removed when IPSec traffic is going through it.

IPv6 version (__xfrm6_bundle_create()) seems to have the same problem. I'll send 
IPv6 version if my analysis and fix are correct :).

Here is IPv4 version (patch is against current linux-2.5 BK).

Signed-off-by: Eugene Surovegin <ebs@ebshome.net>

===== net/ipv4/xfrm4_policy.c 1.8 vs edited =====
--- 1.8/net/ipv4/xfrm4_policy.c	Fri Mar 19 19:35:32 2004
+++ edited/net/ipv4/xfrm4_policy.c	Fri May 28 16:22:35 2004
@@ -87,6 +87,7 @@
 
 		if (unlikely(dst1 == NULL)) {
 			err = -ENOBUFS;
+			nx = i;
 			goto error;
 		}
 
@@ -157,8 +158,14 @@
 	return 0;
 
 error:
-	if (dst)
+	if (dst){
+		/* bump refcount because dst_free will decrement it
+		   and our caller (xfrm_lookup) will do the same on error.
+		*/
+		for (i = 0; i < nx; i++)
+			xfrm_state_hold(xfrm[i]);
 		dst_free(dst);
+	}	
 	return err;
 }
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [IPSEC] fix ref counting in __xfrm4_bundle_create()
  2004-05-29  0:14 [IPSEC] fix ref counting in __xfrm4_bundle_create() Eugene Surovegin
@ 2004-05-29  3:27 ` Herbert Xu
  2004-05-29  4:21   ` Eugene Surovegin
                     ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Herbert Xu @ 2004-05-29  3:27 UTC (permalink / raw)
  To: Eugene Surovegin; +Cc: netdev, davem

Eugene Surovegin <ebs@ebshome.net> wrote:
> 
> Unfortunately, error path in __xfrm4_bundle_create() also calls xfrm_state_put() 
> (indirectly through dst_free() -> ... -> xfrm_dst_destroy()) and we end up 
> calling xfrm_state_put() _twice_.

Well spotted.  Hopefully this should finally put an end to all these
xfrm_state bug reports :)

However, can you see if the following patch fixes this problem as well?
It moves the dst->xfrm assignment to a spot where errors cannot occur.

Cheers,
-- 
Visit Openswan at http://www.openswan.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
--
===== net/ipv4/xfrm4_policy.c 1.8 vs edited =====
--- 1.8/net/ipv4/xfrm4_policy.c	2004-03-20 14:35:32 +11:00
+++ edited/net/ipv4/xfrm4_policy.c	2004-05-29 13:01:39 +10:00
@@ -90,7 +90,6 @@
 			goto error;
 		}
 
-		dst1->xfrm = xfrm[i];
 		if (!dst)
 			dst = dst1;
 		else {
@@ -120,10 +119,12 @@
 		dst_hold(&rt->u.dst);
 	}
 	dst_prev->child = &rt->u.dst;
+	i = 0;
 	for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
 		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
 		x->u.rt.fl = *fl;
 
+		dst_prev->xfrm = xfrm[i++];
 		dst_prev->dev = rt->u.dst.dev;
 		if (rt->u.dst.dev)
 			dev_hold(rt->u.dst.dev);
===== net/ipv6/xfrm6_policy.c 1.16 vs edited =====
--- 1.16/net/ipv6/xfrm6_policy.c	2004-03-20 14:35:32 +11:00
+++ edited/net/ipv6/xfrm6_policy.c	2004-05-29 13:01:51 +10:00
@@ -107,7 +107,6 @@
 			goto error;
 		}
 
-		dst1->xfrm = xfrm[i];
 		if (!dst)
 			dst = dst1;
 		else {
@@ -139,9 +138,11 @@
 		dst_hold(&rt->u.dst);
 	}
 	dst_prev->child = &rt->u.dst;
+	i = 0;
 	for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
 		struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
 
+		dst_prev->xfrm = xfrm[i++];
 		dst_prev->dev = rt->u.dst.dev;
 		if (rt->u.dst.dev)
 			dev_hold(rt->u.dst.dev);
===== net/xfrm/xfrm_policy.c 1.50 vs edited =====
--- 1.50/net/xfrm/xfrm_policy.c	2004-05-23 06:35:06 +10:00
+++ edited/net/xfrm/xfrm_policy.c	2004-05-29 12:52:41 +10:00
@@ -1017,6 +1017,8 @@
 
 static void xfrm_dst_destroy(struct dst_entry *dst)
 {
+	if (!dst->xfrm)
+		return;
 	xfrm_state_put(dst->xfrm);
 	dst->xfrm = NULL;
 }

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [IPSEC] fix ref counting in __xfrm4_bundle_create()
  2004-05-29  3:27 ` Herbert Xu
@ 2004-05-29  4:21   ` Eugene Surovegin
  2004-05-29 19:46   ` David S. Miller
  2004-06-01 20:17   ` Eugene Surovegin
  2 siblings, 0 replies; 5+ messages in thread
From: Eugene Surovegin @ 2004-05-29  4:21 UTC (permalink / raw)
  To: Herbert Xu; +Cc: netdev, davem

On Sat, May 29, 2004 at 01:27:13PM +1000, Herbert Xu wrote:
> However, can you see if the following patch fixes this problem as well?
> It moves the dst->xfrm assignment to a spot where errors cannot occur.

Yeah, looks much nicer than my version.

I'll try to test it tomorrow if I find somebody from QA in the office on 
Saturday :) or only after a long weekend (test setup is quite complicated and I 
cannot reproduce it at home).

Eugene.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [IPSEC] fix ref counting in __xfrm4_bundle_create()
  2004-05-29  3:27 ` Herbert Xu
  2004-05-29  4:21   ` Eugene Surovegin
@ 2004-05-29 19:46   ` David S. Miller
  2004-06-01 20:17   ` Eugene Surovegin
  2 siblings, 0 replies; 5+ messages in thread
From: David S. Miller @ 2004-05-29 19:46 UTC (permalink / raw)
  To: Herbert Xu; +Cc: ebs, netdev

On Sat, 29 May 2004 13:27:13 +1000
Herbert Xu <herbert@gondor.apana.org.au> wrote:

> Well spotted.  Hopefully this should finally put an end to all these
> xfrm_state bug reports :)
> 
> However, can you see if the following patch fixes this problem as well?

I'm applying this patch.  If there is a fixup necessary, just let
me know.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [IPSEC] fix ref counting in __xfrm4_bundle_create()
  2004-05-29  3:27 ` Herbert Xu
  2004-05-29  4:21   ` Eugene Surovegin
  2004-05-29 19:46   ` David S. Miller
@ 2004-06-01 20:17   ` Eugene Surovegin
  2 siblings, 0 replies; 5+ messages in thread
From: Eugene Surovegin @ 2004-06-01 20:17 UTC (permalink / raw)
  To: Herbert Xu; +Cc: netdev, davem

On Sat, May 29, 2004 at 01:27:13PM +1000, Herbert Xu wrote:
> However, can you see if the following patch fixes this problem as well?
> It moves the dst->xfrm assignment to a spot where errors cannot occur.

Yes, your version is OK. We haven't got the crash during our testing.

Thanks a lot, Herbert.

Eugene

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2004-06-01 20:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-29  0:14 [IPSEC] fix ref counting in __xfrm4_bundle_create() Eugene Surovegin
2004-05-29  3:27 ` Herbert Xu
2004-05-29  4:21   ` Eugene Surovegin
2004-05-29 19:46   ` David S. Miller
2004-06-01 20:17   ` Eugene Surovegin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).