Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2640

kernel-2.6.18-238.el5.src.rpm

From: Jiri Pirko <jpirko@redhat.com>
Date: Wed, 28 Jan 2009 17:07:43 +0100
Subject: [net] fix icmp_send and icmpv6_send host re-lookup code
Message-id: 20090128160742.GB3553@psychotron.englab.brq.redhat.com
O-Subject: [RHEL5.4 patch] BZ439670 net: fix icmp_send and icmpv6_send host re-lookup code
Bugzilla: 439670
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: Herbert Xu <herbert.xu@redhat.com>
RH-Acked-by: David Miller <davem@redhat.com>

BZ439670
https://bugzilla.redhat.com/show_bug.cgi?id=439670

This patch is a backport of following two upstream patches:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7c0ecc4c4f8fd90988aab8a95297b9c0038b6160

From: Pavel Emelyanov <xemul@openvz.org>
Date: Wed, 26 Mar 2008 09:27:09 +0000 (-0700)

	[ICMP]: Dst entry leak in icmp_send host re-lookup code (v2).

	Commit 8b7817f3a959ed99d7443afc12f78a7e1fcc2063 ([IPSEC]: Add ICMP host
	relookup support) introduced some dst leaks on error paths: the rt
	pointer can be forgotten to be put. Fix it bu going to a proper label.

	Found after net namespace's lo refused to unregister :) Many thanks to
	Den for valuable help during debugging.

	Herbert pointed out, that xfrm_lookup() will put the rtable in case
	of error itself, so the first goto fix is redundant.

	Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
	Signed-off-by: Denis V. Lunev <den@openvz.org>
	Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 56558b7..69c7734 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -590,7 +590,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
 
 			fl2.fl4_dst = fl.fl4_src;
 			if (ip_route_output_key(&rt2, &fl2))
-				goto out_unlock;
+				goto relookup_failed;
 
 			/* Ugh! */
 			odst = skb_in->dst;
@@ -603,21 +603,23 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
 		}
 
 		if (err)
-			goto out_unlock;
+			goto relookup_failed;
 
 		err = xfrm_lookup((struct dst_entry **)&rt2, &fl, NULL,
 				  XFRM_LOOKUP_ICMP);
-		if (err == -ENOENT) {
+		switch (err) {
+		case 0:
+			dst_release(&rt->u.dst);
+			rt = rt2;
+			break;
+		case -EPERM:
+			goto ende;
+		default:
+relookup_failed:
 			if (!rt)
 				goto out_unlock;
-			goto route_done;
+			break;
 		}
-
-		dst_release(&rt->u.dst);
-		rt = rt2;
-
-		if (err)
-			goto out_unlock;
 	}
 
 route_done:
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 388eb7d..2c73690 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -414,22 +414,23 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
 	xfrm6_decode_session_reverse(skb, &fl2);
 
 	if (ip6_dst_lookup(sk, &dst2, &fl2))
-		goto out;
+		goto relookup_failed;
 
 	err = xfrm_nlookup(&dst2, &fl2, sk, XFRM_LOOKUP_ICMP);
-	if (err == -ENOENT || err == -ENOSYS) {
-		err = -ENOENT;
+	switch (err) {
+	case 0:
+		dst_release(dst);
+		dst = dst2;
+		break;
+	case -EPERM:
+		goto out_dst_release;
+	default:
+relookup_failed:
 		if (!dst)
 			goto out;
-		goto route_done;
+		break;
 	}
 
-	dst_release(dst);
-	dst = dst2;
-
-	if (err)
-		goto out;
-
 route_done:
 	if (ipv6_addr_is_multicast(&fl.fl6_dst))
 		hlimit = np->mcast_hops;