aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c68
1 files changed, 53 insertions, 15 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 2a7861661f14..fffdd34f3baf 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -883,30 +883,32 @@ out:
883} 883}
884EXPORT_SYMBOL(xfrm_policy_walk); 884EXPORT_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 */
888static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, 891static 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
907static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, 908static 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);
958fail:
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
946static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, 964static 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
959end: 985end:
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
965static inline int policy_to_flow_dir(int dir) 992static inline int policy_to_flow_dir(int dir)
@@ -1297,6 +1324,8 @@ restart:
1297 1324
1298 policy = flow_cache_lookup(fl, dst_orig->ops->family, 1325 policy = flow_cache_lookup(fl, dst_orig->ops->family,
1299 dir, xfrm_policy_lookup); 1326 dir, xfrm_policy_lookup);
1327 if (IS_ERR(policy))
1328 return PTR_ERR(policy);
1300 } 1329 }
1301 1330
1302 if (!policy) 1331 if (!policy)
@@ -1343,6 +1372,10 @@ restart:
1343 fl, family, 1372 fl, family,
1344 XFRM_POLICY_OUT); 1373 XFRM_POLICY_OUT);
1345 if (pols[1]) { 1374 if (pols[1]) {
1375 if (IS_ERR(pols[1])) {
1376 err = PTR_ERR(pols[1]);
1377 goto error;
1378 }
1346 if (pols[1]->action == XFRM_POLICY_BLOCK) { 1379 if (pols[1]->action == XFRM_POLICY_BLOCK) {
1347 err = -EPERM; 1380 err = -EPERM;
1348 goto error; 1381 goto error;
@@ -1581,6 +1614,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1581 pol = flow_cache_lookup(&fl, family, fl_dir, 1614 pol = flow_cache_lookup(&fl, family, fl_dir,
1582 xfrm_policy_lookup); 1615 xfrm_policy_lookup);
1583 1616
1617 if (IS_ERR(pol))
1618 return 0;
1619
1584 if (!pol) { 1620 if (!pol) {
1585 if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { 1621 if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
1586 xfrm_secpath_reject(xerr_idx, skb, &fl); 1622 xfrm_secpath_reject(xerr_idx, skb, &fl);
@@ -1599,6 +1635,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1599 &fl, family, 1635 &fl, family,
1600 XFRM_POLICY_IN); 1636 XFRM_POLICY_IN);
1601 if (pols[1]) { 1637 if (pols[1]) {
1638 if (IS_ERR(pols[1]))
1639 return 0;
1602 pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; 1640 pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec;
1603 npols ++; 1641 npols ++;
1604 } 1642 }