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 <[EMAIL PROTECTED]>
---

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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to