lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 6 Sep 2007 19:00:10 +0300
From:	Joakim Koskela <joakim.koskela@...t.fi>
To:	netdev@...r.kernel.org
Subject: [PATCH net-2.6.23-rc5] ipsec interfamily route handling fix

Hi,

This patch addresses a couple of issues related to interfamily ipsec
modes. The problem is that the structure of the routing info changes
with the family during the __xfrmX_bundle_create, which hasn't been
taken properly into account. Seems that by coincidence it hasn't
caused problems on 32bit platforms, but crashes for example on x86_64
in 6-4 around line 209 of xfrm6_policy.c as rt doesn't point to a
rt6_info anymore, but actually a struct rtable. With 64bit pointers,
the rt->rt6i_node pointer seems to hit something usually not null in
the rtable that rt now points to, making it go for the path_cookie
assignment and subsequently crashing.

Tested on both 32/64bit with all four (44/46/64/66) combinations of
transformation. I'm still a bit worried about how for example nested
transformations work with all of this and would appreciate if someone
more familiar with the details of these structs could comment.

Signed-off-by: Joakim Koskela <jookos@...il.com>
---

diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 4ff8ed3..7410c0d 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -72,6 +72,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct 
xfrm_state **xfrm, int
 	struct dst_entry *dst, *dst_prev;
 	struct rtable *rt0 = (struct rtable*)(*dst_p);
 	struct rtable *rt = rt0;
+	unsigned short encap_family = AF_INET;
 	struct flowi fl_tunnel = {
 		.nl_u = {
 			.ip4_u = {
@@ -118,7 +119,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct 
xfrm_state **xfrm, int
 		trailer_len += xfrm[i]->props.trailer_len;
 
 		if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
-			unsigned short encap_family = xfrm[i]->props.family;
+			encap_family = xfrm[i]->props.family;
 			switch (encap_family) {
 			case AF_INET:
 				fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
@@ -180,16 +181,19 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct 
xfrm_state **xfrm, int
 		}
 		dst_prev->output = afinfo->output;
 		xfrm_state_put_afinfo(afinfo);
-		if (dst_prev->xfrm->props.family == AF_INET && rt->peer)
-			atomic_inc(&rt->peer->refcnt);
-		x->u.rt.peer = rt->peer;
+
+		if (encap_family == AF_INET) {
+			if (dst_prev->xfrm->props.family == AF_INET && rt->peer)
+				atomic_inc(&rt->peer->refcnt);
+			x->u.rt.peer = rt->peer;
+			x->u.rt.rt_type = rt->rt_type;
+			x->u.rt.rt_gateway = rt->rt_gateway;
+		}
 		/* Sheit... I remember I did this right. Apparently,
 		 * it was magically lost, so this code needs audit */
 		x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|
RTCF_LOCAL);
-		x->u.rt.rt_type = rt->rt_type;
 		x->u.rt.rt_src = rt0->rt_src;
 		x->u.rt.rt_dst = rt0->rt_dst;
-		x->u.rt.rt_gateway = rt->rt_gateway;
 		x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
 		x->u.rt.idev = rt0->idev;
 		in_dev_hold(rt0->idev);
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 3ec0c47..9733f39 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -131,6 +131,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct 
xfrm_state **xfrm, int
 	struct dst_entry *dst, *dst_prev;
 	struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
 	struct rt6_info *rt  = rt0;
+	unsigned short encap_family = AF_INET6;
 	struct flowi fl_tunnel = {
 		.nl_u = {
 			.ip6_u = {
@@ -180,11 +181,13 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct 
xfrm_state **xfrm, int
 
 		if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL ||
 		    xfrm[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) {
-			unsigned short encap_family = xfrm[i]->props.family;
+			encap_family = xfrm[i]->props.family;
 			switch(encap_family) {
 			case AF_INET:
 				fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
 				fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
+				fl_tunnel.fl4_tos = 0;
+				fl_tunnel.fl4_scope = 0;
 				break;
 			case AF_INET6:
 				ipv6_addr_copy(&fl_tunnel.fl6_dst, __xfrm6_bundle_addr_remote(xfrm[i], 
&fl->fl6_dst));
@@ -205,7 +208,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct 
xfrm_state **xfrm, int
 
 	dst_prev->child = &rt->u.dst;
 	dst->path = &rt->u.dst;
-	if (rt->rt6i_node)
+	if (encap_family == AF_INET6 && rt->rt6i_node)
 		((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum;
 
 	*dst_p = dst;
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists