diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 101 |
1 files changed, 75 insertions, 26 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 2a7861661f14..7736b23c3f03 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -883,30 +883,32 @@ out: | |||
883 | } | 883 | } |
884 | EXPORT_SYMBOL(xfrm_policy_walk); | 884 | EXPORT_SYMBOL(xfrm_policy_walk); |
885 | 885 | ||
886 | /* Find policy to apply to this flow. */ | 886 | /* |
887 | 887 | * Find policy to apply to this flow. | |
888 | * | ||
889 | * Returns 0 if policy found, else an -errno. | ||
890 | */ | ||
888 | static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, | 891 | static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, |
889 | u8 type, u16 family, int dir) | 892 | u8 type, u16 family, int dir) |
890 | { | 893 | { |
891 | struct xfrm_selector *sel = &pol->selector; | 894 | struct xfrm_selector *sel = &pol->selector; |
892 | int match; | 895 | int match, ret = -ESRCH; |
893 | 896 | ||
894 | if (pol->family != family || | 897 | if (pol->family != family || |
895 | pol->type != type) | 898 | pol->type != type) |
896 | return 0; | 899 | return ret; |
897 | 900 | ||
898 | match = xfrm_selector_match(sel, fl, family); | 901 | match = xfrm_selector_match(sel, fl, family); |
899 | if (match) { | 902 | if (match) |
900 | if (!security_xfrm_policy_lookup(pol, fl->secid, dir)) | 903 | ret = security_xfrm_policy_lookup(pol, fl->secid, dir); |
901 | return 1; | ||
902 | } | ||
903 | 904 | ||
904 | return 0; | 905 | return ret; |
905 | } | 906 | } |
906 | 907 | ||
907 | static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, | 908 | static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, |
908 | u16 family, u8 dir) | 909 | u16 family, u8 dir) |
909 | { | 910 | { |
911 | int err; | ||
910 | struct xfrm_policy *pol, *ret; | 912 | struct xfrm_policy *pol, *ret; |
911 | xfrm_address_t *daddr, *saddr; | 913 | xfrm_address_t *daddr, *saddr; |
912 | struct hlist_node *entry; | 914 | struct hlist_node *entry; |
@@ -922,7 +924,15 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, | |||
922 | chain = policy_hash_direct(daddr, saddr, family, dir); | 924 | chain = policy_hash_direct(daddr, saddr, family, dir); |
923 | ret = NULL; | 925 | ret = NULL; |
924 | hlist_for_each_entry(pol, entry, chain, bydst) { | 926 | hlist_for_each_entry(pol, entry, chain, bydst) { |
925 | if (xfrm_policy_match(pol, fl, type, family, dir)) { | 927 | err = xfrm_policy_match(pol, fl, type, family, dir); |
928 | if (err) { | ||
929 | if (err == -ESRCH) | ||
930 | continue; | ||
931 | else { | ||
932 | ret = ERR_PTR(err); | ||
933 | goto fail; | ||
934 | } | ||
935 | } else { | ||
926 | ret = pol; | 936 | ret = pol; |
927 | priority = ret->priority; | 937 | priority = ret->priority; |
928 | break; | 938 | break; |
@@ -930,36 +940,53 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, | |||
930 | } | 940 | } |
931 | chain = &xfrm_policy_inexact[dir]; | 941 | chain = &xfrm_policy_inexact[dir]; |
932 | hlist_for_each_entry(pol, entry, chain, bydst) { | 942 | hlist_for_each_entry(pol, entry, chain, bydst) { |
933 | if (xfrm_policy_match(pol, fl, type, family, dir) && | 943 | err = xfrm_policy_match(pol, fl, type, family, dir); |
934 | pol->priority < priority) { | 944 | if (err) { |
945 | if (err == -ESRCH) | ||
946 | continue; | ||
947 | else { | ||
948 | ret = ERR_PTR(err); | ||
949 | goto fail; | ||
950 | } | ||
951 | } else if (pol->priority < priority) { | ||
935 | ret = pol; | 952 | ret = pol; |
936 | break; | 953 | break; |
937 | } | 954 | } |
938 | } | 955 | } |
939 | if (ret) | 956 | if (ret) |
940 | xfrm_pol_hold(ret); | 957 | xfrm_pol_hold(ret); |
958 | fail: | ||
941 | read_unlock_bh(&xfrm_policy_lock); | 959 | read_unlock_bh(&xfrm_policy_lock); |
942 | 960 | ||
943 | return ret; | 961 | return ret; |
944 | } | 962 | } |
945 | 963 | ||
946 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | 964 | static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, |
947 | void **objp, atomic_t **obj_refp) | 965 | void **objp, atomic_t **obj_refp) |
948 | { | 966 | { |
949 | struct xfrm_policy *pol; | 967 | struct xfrm_policy *pol; |
968 | int err = 0; | ||
950 | 969 | ||
951 | #ifdef CONFIG_XFRM_SUB_POLICY | 970 | #ifdef CONFIG_XFRM_SUB_POLICY |
952 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); | 971 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); |
953 | if (pol) | 972 | if (IS_ERR(pol)) { |
973 | err = PTR_ERR(pol); | ||
974 | pol = NULL; | ||
975 | } | ||
976 | if (pol || err) | ||
954 | goto end; | 977 | goto end; |
955 | #endif | 978 | #endif |
956 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); | 979 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); |
957 | 980 | if (IS_ERR(pol)) { | |
981 | err = PTR_ERR(pol); | ||
982 | pol = NULL; | ||
983 | } | ||
958 | #ifdef CONFIG_XFRM_SUB_POLICY | 984 | #ifdef CONFIG_XFRM_SUB_POLICY |
959 | end: | 985 | end: |
960 | #endif | 986 | #endif |
961 | if ((*objp = (void *) pol) != NULL) | 987 | if ((*objp = (void *) pol) != NULL) |
962 | *obj_refp = &pol->refcnt; | 988 | *obj_refp = &pol->refcnt; |
989 | return err; | ||
963 | } | 990 | } |
964 | 991 | ||
965 | static inline int policy_to_flow_dir(int dir) | 992 | static inline int policy_to_flow_dir(int dir) |
@@ -989,12 +1016,16 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
989 | sk->sk_family); | 1016 | sk->sk_family); |
990 | int err = 0; | 1017 | int err = 0; |
991 | 1018 | ||
992 | if (match) | 1019 | if (match) { |
993 | err = security_xfrm_policy_lookup(pol, fl->secid, policy_to_flow_dir(dir)); | 1020 | err = security_xfrm_policy_lookup(pol, fl->secid, |
994 | 1021 | policy_to_flow_dir(dir)); | |
995 | if (match && !err) | 1022 | if (!err) |
996 | xfrm_pol_hold(pol); | 1023 | xfrm_pol_hold(pol); |
997 | else | 1024 | else if (err == -ESRCH) |
1025 | pol = NULL; | ||
1026 | else | ||
1027 | pol = ERR_PTR(err); | ||
1028 | } else | ||
998 | pol = NULL; | 1029 | pol = NULL; |
999 | } | 1030 | } |
1000 | read_unlock_bh(&xfrm_policy_lock); | 1031 | read_unlock_bh(&xfrm_policy_lock); |
@@ -1286,8 +1317,11 @@ restart: | |||
1286 | pol_dead = 0; | 1317 | pol_dead = 0; |
1287 | xfrm_nr = 0; | 1318 | xfrm_nr = 0; |
1288 | 1319 | ||
1289 | if (sk && sk->sk_policy[1]) | 1320 | if (sk && sk->sk_policy[1]) { |
1290 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | 1321 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
1322 | if (IS_ERR(policy)) | ||
1323 | return PTR_ERR(policy); | ||
1324 | } | ||
1291 | 1325 | ||
1292 | if (!policy) { | 1326 | if (!policy) { |
1293 | /* To accelerate a bit... */ | 1327 | /* To accelerate a bit... */ |
@@ -1297,6 +1331,8 @@ restart: | |||
1297 | 1331 | ||
1298 | policy = flow_cache_lookup(fl, dst_orig->ops->family, | 1332 | policy = flow_cache_lookup(fl, dst_orig->ops->family, |
1299 | dir, xfrm_policy_lookup); | 1333 | dir, xfrm_policy_lookup); |
1334 | if (IS_ERR(policy)) | ||
1335 | return PTR_ERR(policy); | ||
1300 | } | 1336 | } |
1301 | 1337 | ||
1302 | if (!policy) | 1338 | if (!policy) |
@@ -1343,6 +1379,10 @@ restart: | |||
1343 | fl, family, | 1379 | fl, family, |
1344 | XFRM_POLICY_OUT); | 1380 | XFRM_POLICY_OUT); |
1345 | if (pols[1]) { | 1381 | if (pols[1]) { |
1382 | if (IS_ERR(pols[1])) { | ||
1383 | err = PTR_ERR(pols[1]); | ||
1384 | goto error; | ||
1385 | } | ||
1346 | if (pols[1]->action == XFRM_POLICY_BLOCK) { | 1386 | if (pols[1]->action == XFRM_POLICY_BLOCK) { |
1347 | err = -EPERM; | 1387 | err = -EPERM; |
1348 | goto error; | 1388 | goto error; |
@@ -1574,13 +1614,19 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1574 | } | 1614 | } |
1575 | 1615 | ||
1576 | pol = NULL; | 1616 | pol = NULL; |
1577 | if (sk && sk->sk_policy[dir]) | 1617 | if (sk && sk->sk_policy[dir]) { |
1578 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); | 1618 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); |
1619 | if (IS_ERR(pol)) | ||
1620 | return 0; | ||
1621 | } | ||
1579 | 1622 | ||
1580 | if (!pol) | 1623 | if (!pol) |
1581 | pol = flow_cache_lookup(&fl, family, fl_dir, | 1624 | pol = flow_cache_lookup(&fl, family, fl_dir, |
1582 | xfrm_policy_lookup); | 1625 | xfrm_policy_lookup); |
1583 | 1626 | ||
1627 | if (IS_ERR(pol)) | ||
1628 | return 0; | ||
1629 | |||
1584 | if (!pol) { | 1630 | if (!pol) { |
1585 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { | 1631 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { |
1586 | xfrm_secpath_reject(xerr_idx, skb, &fl); | 1632 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
@@ -1599,6 +1645,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1599 | &fl, family, | 1645 | &fl, family, |
1600 | XFRM_POLICY_IN); | 1646 | XFRM_POLICY_IN); |
1601 | if (pols[1]) { | 1647 | if (pols[1]) { |
1648 | if (IS_ERR(pols[1])) | ||
1649 | return 0; | ||
1602 | pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; | 1650 | pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; |
1603 | npols ++; | 1651 | npols ++; |
1604 | } | 1652 | } |
@@ -1706,7 +1754,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) | |||
1706 | 1754 | ||
1707 | static int stale_bundle(struct dst_entry *dst) | 1755 | static int stale_bundle(struct dst_entry *dst) |
1708 | { | 1756 | { |
1709 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); | 1757 | return !xfrm_bundle_ok(NULL, (struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); |
1710 | } | 1758 | } |
1711 | 1759 | ||
1712 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) | 1760 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) |
@@ -1828,7 +1876,8 @@ EXPORT_SYMBOL(xfrm_init_pmtu); | |||
1828 | * still valid. | 1876 | * still valid. |
1829 | */ | 1877 | */ |
1830 | 1878 | ||
1831 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict) | 1879 | int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, |
1880 | struct flowi *fl, int family, int strict) | ||
1832 | { | 1881 | { |
1833 | struct dst_entry *dst = &first->u.dst; | 1882 | struct dst_entry *dst = &first->u.dst; |
1834 | struct xfrm_dst *last; | 1883 | struct xfrm_dst *last; |
@@ -1845,7 +1894,7 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int str | |||
1845 | 1894 | ||
1846 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) | 1895 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) |
1847 | return 0; | 1896 | return 0; |
1848 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm)) | 1897 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol)) |
1849 | return 0; | 1898 | return 0; |
1850 | if (dst->xfrm->km.state != XFRM_STATE_VALID) | 1899 | if (dst->xfrm->km.state != XFRM_STATE_VALID) |
1851 | return 0; | 1900 | return 0; |