aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2006-08-23 22:12:01 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:06:44 -0400
commite53820de0f81da1429048634cadc6ef5f50c2f8b (patch)
tree7a63689f564c0719a0d4fea2cc5d3b84ea00fbbd
parent9afaca057980c02771f4657c455cc7592fcd7373 (diff)
[XFRM] IPV6: Restrict bundle reusing
For outbound transformation, bundle is checked whether it is suitable for current flow to be reused or not. In such IPv6 case as below, transformation may apply incorrect bundle for the flow instead of creating another bundle: - The policy selector has destination prefix length < 128 (Two or more addresses can be matched it) - Its bundle holds dst entry of default route whose prefix length < 128 (Previous traffic was used such route as next hop) - The policy and the bundle were used a transport mode state and this time flow address is not matched the bundled state. This issue is found by Mobile IPv6 usage to protect mobility signaling by IPsec, but it is not a Mobile IPv6 specific. This patch adds strict check to xfrm_bundle_ok() for each state mode and address when prefix length is less than 128. Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/xfrm.h19
-rw-r--r--net/ipv4/xfrm4_policy.c2
-rw-r--r--net/ipv6/xfrm6_policy.c4
-rw-r--r--net/xfrm/xfrm_policy.c8
4 files changed, 28 insertions, 5 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 248874ecf8df..7f1630630dcf 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -869,6 +869,23 @@ xfrm_state_addr_check(struct xfrm_state *x,
869 return 0; 869 return 0;
870} 870}
871 871
872static __inline__ int
873xfrm_state_addr_flow_check(struct xfrm_state *x, struct flowi *fl,
874 unsigned short family)
875{
876 switch (family) {
877 case AF_INET:
878 return __xfrm4_state_addr_check(x,
879 (xfrm_address_t *)&fl->fl4_dst,
880 (xfrm_address_t *)&fl->fl4_src);
881 case AF_INET6:
882 return __xfrm6_state_addr_check(x,
883 (xfrm_address_t *)&fl->fl6_dst,
884 (xfrm_address_t *)&fl->fl6_src);
885 }
886 return 0;
887}
888
872static inline int xfrm_state_kern(struct xfrm_state *x) 889static inline int xfrm_state_kern(struct xfrm_state *x)
873{ 890{
874 return atomic_read(&x->tunnel_users); 891 return atomic_read(&x->tunnel_users);
@@ -1014,7 +1031,7 @@ extern void xfrm_policy_flush(void);
1014extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); 1031extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
1015extern int xfrm_flush_bundles(void); 1032extern int xfrm_flush_bundles(void);
1016extern void xfrm_flush_all_bundles(void); 1033extern void xfrm_flush_all_bundles(void);
1017extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family); 1034extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family, int strict);
1018extern void xfrm_init_pmtu(struct dst_entry *dst); 1035extern void xfrm_init_pmtu(struct dst_entry *dst);
1019 1036
1020extern wait_queue_head_t km_waitq; 1037extern wait_queue_head_t km_waitq;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index e517981ceadd..42d8ded0f96a 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -33,7 +33,7 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
33 xdst->u.rt.fl.fl4_dst == fl->fl4_dst && 33 xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
34 xdst->u.rt.fl.fl4_src == fl->fl4_src && 34 xdst->u.rt.fl.fl4_src == fl->fl4_src &&
35 xdst->u.rt.fl.fl4_tos == fl->fl4_tos && 35 xdst->u.rt.fl.fl4_tos == fl->fl4_tos &&
36 xfrm_bundle_ok(xdst, fl, AF_INET)) { 36 xfrm_bundle_ok(xdst, fl, AF_INET, 0)) {
37 dst_clone(dst); 37 dst_clone(dst);
38 break; 38 break;
39 } 39 }
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index a3f68c8b737e..729b4748d6d3 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -50,7 +50,9 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
50 xdst->u.rt6.rt6i_src.plen); 50 xdst->u.rt6.rt6i_src.plen);
51 if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && 51 if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) &&
52 ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && 52 ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) &&
53 xfrm_bundle_ok(xdst, fl, AF_INET6)) { 53 xfrm_bundle_ok(xdst, fl, AF_INET6,
54 (xdst->u.rt6.rt6i_dst.plen != 128 ||
55 xdst->u.rt6.rt6i_src.plen != 128))) {
54 dst_clone(dst); 56 dst_clone(dst);
55 break; 57 break;
56 } 58 }
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 56abb5c057d4..ad2a5cba1f5b 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1167,7 +1167,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
1167 1167
1168static int stale_bundle(struct dst_entry *dst) 1168static int stale_bundle(struct dst_entry *dst)
1169{ 1169{
1170 return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC); 1170 return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0);
1171} 1171}
1172 1172
1173void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) 1173void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
@@ -1282,7 +1282,7 @@ EXPORT_SYMBOL(xfrm_init_pmtu);
1282 * still valid. 1282 * still valid.
1283 */ 1283 */
1284 1284
1285int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) 1285int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict)
1286{ 1286{
1287 struct dst_entry *dst = &first->u.dst; 1287 struct dst_entry *dst = &first->u.dst;
1288 struct xfrm_dst *last; 1288 struct xfrm_dst *last;
@@ -1304,6 +1304,10 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family)
1304 if (dst->xfrm->km.state != XFRM_STATE_VALID) 1304 if (dst->xfrm->km.state != XFRM_STATE_VALID)
1305 return 0; 1305 return 0;
1306 1306
1307 if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL &&
1308 !xfrm_state_addr_flow_check(dst->xfrm, fl, family))
1309 return 0;
1310
1307 mtu = dst_mtu(dst->child); 1311 mtu = dst_mtu(dst->child);
1308 if (xdst->child_mtu_cached != mtu) { 1312 if (xdst->child_mtu_cached != mtu) {
1309 last = xdst; 1313 last = xdst;