aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c156
1 files changed, 103 insertions, 53 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 9fc4c315f6cd..ab4d0e598a2c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex);
46 46
47static DEFINE_RWLOCK(xfrm_policy_lock); 47static DEFINE_RWLOCK(xfrm_policy_lock);
48 48
49static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX];
49unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; 50unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
50EXPORT_SYMBOL(xfrm_policy_count); 51EXPORT_SYMBOL(xfrm_policy_count);
51 52
@@ -96,25 +97,52 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
96 return 0; 97 return 0;
97} 98}
98 99
100static inline struct dst_entry *__xfrm_dst_lookup(int tos,
101 xfrm_address_t *saddr,
102 xfrm_address_t *daddr,
103 int family)
104{
105 struct xfrm_policy_afinfo *afinfo;
106 struct dst_entry *dst;
107
108 afinfo = xfrm_policy_get_afinfo(family);
109 if (unlikely(afinfo == NULL))
110 return ERR_PTR(-EAFNOSUPPORT);
111
112 dst = afinfo->dst_lookup(tos, saddr, daddr);
113
114 xfrm_policy_put_afinfo(afinfo);
115
116 return dst;
117}
118
99static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, 119static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
120 xfrm_address_t *prev_saddr,
121 xfrm_address_t *prev_daddr,
100 int family) 122 int family)
101{ 123{
102 xfrm_address_t *saddr = &x->props.saddr; 124 xfrm_address_t *saddr = &x->props.saddr;
103 xfrm_address_t *daddr = &x->id.daddr; 125 xfrm_address_t *daddr = &x->id.daddr;
104 struct xfrm_policy_afinfo *afinfo;
105 struct dst_entry *dst; 126 struct dst_entry *dst;
106 127
107 if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) 128 if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
108 saddr = x->coaddr; 129 saddr = x->coaddr;
109 if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) 130 daddr = prev_daddr;
131 }
132 if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
133 saddr = prev_saddr;
110 daddr = x->coaddr; 134 daddr = x->coaddr;
135 }
111 136
112 afinfo = xfrm_policy_get_afinfo(family); 137 dst = __xfrm_dst_lookup(tos, saddr, daddr, family);
113 if (unlikely(afinfo == NULL)) 138
114 return ERR_PTR(-EAFNOSUPPORT); 139 if (!IS_ERR(dst)) {
140 if (prev_saddr != saddr)
141 memcpy(prev_saddr, saddr, sizeof(*prev_saddr));
142 if (prev_daddr != daddr)
143 memcpy(prev_daddr, daddr, sizeof(*prev_daddr));
144 }
115 145
116 dst = afinfo->dst_lookup(tos, saddr, daddr);
117 xfrm_policy_put_afinfo(afinfo);
118 return dst; 146 return dst;
119} 147}
120 148
@@ -208,6 +236,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
208 policy = kzalloc(sizeof(struct xfrm_policy), gfp); 236 policy = kzalloc(sizeof(struct xfrm_policy), gfp);
209 237
210 if (policy) { 238 if (policy) {
239 INIT_LIST_HEAD(&policy->bytype);
211 INIT_HLIST_NODE(&policy->bydst); 240 INIT_HLIST_NODE(&policy->bydst);
212 INIT_HLIST_NODE(&policy->byidx); 241 INIT_HLIST_NODE(&policy->byidx);
213 rwlock_init(&policy->lock); 242 rwlock_init(&policy->lock);
@@ -230,7 +259,11 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
230 if (del_timer(&policy->timer)) 259 if (del_timer(&policy->timer))
231 BUG(); 260 BUG();
232 261
233 security_xfrm_policy_free(policy); 262 write_lock_bh(&xfrm_policy_lock);
263 list_del(&policy->bytype);
264 write_unlock_bh(&xfrm_policy_lock);
265
266 security_xfrm_policy_free(policy->security);
234 kfree(policy); 267 kfree(policy);
235} 268}
236EXPORT_SYMBOL(xfrm_policy_destroy); 269EXPORT_SYMBOL(xfrm_policy_destroy);
@@ -584,6 +617,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
584 policy->curlft.use_time = 0; 617 policy->curlft.use_time = 0;
585 if (!mod_timer(&policy->timer, jiffies + HZ)) 618 if (!mod_timer(&policy->timer, jiffies + HZ))
586 xfrm_pol_hold(policy); 619 xfrm_pol_hold(policy);
620 list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]);
587 write_unlock_bh(&xfrm_policy_lock); 621 write_unlock_bh(&xfrm_policy_lock);
588 622
589 if (delpol) 623 if (delpol)
@@ -642,7 +676,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
642 xfrm_sec_ctx_match(ctx, pol->security)) { 676 xfrm_sec_ctx_match(ctx, pol->security)) {
643 xfrm_pol_hold(pol); 677 xfrm_pol_hold(pol);
644 if (delete) { 678 if (delete) {
645 *err = security_xfrm_policy_delete(pol); 679 *err = security_xfrm_policy_delete(
680 pol->security);
646 if (*err) { 681 if (*err) {
647 write_unlock_bh(&xfrm_policy_lock); 682 write_unlock_bh(&xfrm_policy_lock);
648 return pol; 683 return pol;
@@ -684,7 +719,8 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,
684 if (pol->type == type && pol->index == id) { 719 if (pol->type == type && pol->index == id) {
685 xfrm_pol_hold(pol); 720 xfrm_pol_hold(pol);
686 if (delete) { 721 if (delete) {
687 *err = security_xfrm_policy_delete(pol); 722 *err = security_xfrm_policy_delete(
723 pol->security);
688 if (*err) { 724 if (*err) {
689 write_unlock_bh(&xfrm_policy_lock); 725 write_unlock_bh(&xfrm_policy_lock);
690 return pol; 726 return pol;
@@ -722,7 +758,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
722 &xfrm_policy_inexact[dir], bydst) { 758 &xfrm_policy_inexact[dir], bydst) {
723 if (pol->type != type) 759 if (pol->type != type)
724 continue; 760 continue;
725 err = security_xfrm_policy_delete(pol); 761 err = security_xfrm_policy_delete(pol->security);
726 if (err) { 762 if (err) {
727 xfrm_audit_policy_delete(pol, 0, 763 xfrm_audit_policy_delete(pol, 0,
728 audit_info->loginuid, 764 audit_info->loginuid,
@@ -736,7 +772,8 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
736 bydst) { 772 bydst) {
737 if (pol->type != type) 773 if (pol->type != type)
738 continue; 774 continue;
739 err = security_xfrm_policy_delete(pol); 775 err = security_xfrm_policy_delete(
776 pol->security);
740 if (err) { 777 if (err) {
741 xfrm_audit_policy_delete(pol, 0, 778 xfrm_audit_policy_delete(pol, 0,
742 audit_info->loginuid, 779 audit_info->loginuid,
@@ -822,57 +859,60 @@ out:
822} 859}
823EXPORT_SYMBOL(xfrm_policy_flush); 860EXPORT_SYMBOL(xfrm_policy_flush);
824 861
825int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), 862int xfrm_policy_walk(struct xfrm_policy_walk *walk,
863 int (*func)(struct xfrm_policy *, int, int, void*),
826 void *data) 864 void *data)
827{ 865{
828 struct xfrm_policy *pol, *last = NULL; 866 struct xfrm_policy *old, *pol, *last = NULL;
829 struct hlist_node *entry; 867 int error = 0;
830 int dir, last_dir = 0, count, error;
831 868
869 if (walk->type >= XFRM_POLICY_TYPE_MAX &&
870 walk->type != XFRM_POLICY_TYPE_ANY)
871 return -EINVAL;
872
873 if (walk->policy == NULL && walk->count != 0)
874 return 0;
875
876 old = pol = walk->policy;
877 walk->policy = NULL;
832 read_lock_bh(&xfrm_policy_lock); 878 read_lock_bh(&xfrm_policy_lock);
833 count = 0;
834 879
835 for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { 880 for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
836 struct hlist_head *table = xfrm_policy_bydst[dir].table; 881 if (walk->type != walk->cur_type &&
837 int i; 882 walk->type != XFRM_POLICY_TYPE_ANY)
883 continue;
838 884
839 hlist_for_each_entry(pol, entry, 885 if (pol == NULL) {
840 &xfrm_policy_inexact[dir], bydst) { 886 pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
841 if (pol->type != type) 887 struct xfrm_policy, bytype);
888 }
889 list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
890 if (pol->dead)
842 continue; 891 continue;
843 if (last) { 892 if (last) {
844 error = func(last, last_dir % XFRM_POLICY_MAX, 893 error = func(last, xfrm_policy_id2dir(last->index),
845 count, data); 894 walk->count, data);
846 if (error) 895 if (error) {
896 xfrm_pol_hold(last);
897 walk->policy = last;
847 goto out; 898 goto out;
848 }
849 last = pol;
850 last_dir = dir;
851 count++;
852 }
853 for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
854 hlist_for_each_entry(pol, entry, table + i, bydst) {
855 if (pol->type != type)
856 continue;
857 if (last) {
858 error = func(last, last_dir % XFRM_POLICY_MAX,
859 count, data);
860 if (error)
861 goto out;
862 } 899 }
863 last = pol;
864 last_dir = dir;
865 count++;
866 } 900 }
901 last = pol;
902 walk->count++;
867 } 903 }
904 pol = NULL;
868 } 905 }
869 if (count == 0) { 906 if (walk->count == 0) {
870 error = -ENOENT; 907 error = -ENOENT;
871 goto out; 908 goto out;
872 } 909 }
873 error = func(last, last_dir % XFRM_POLICY_MAX, 0, data); 910 if (last)
911 error = func(last, xfrm_policy_id2dir(last->index), 0, data);
874out: 912out:
875 read_unlock_bh(&xfrm_policy_lock); 913 read_unlock_bh(&xfrm_policy_lock);
914 if (old != NULL)
915 xfrm_pol_put(old);
876 return error; 916 return error;
877} 917}
878EXPORT_SYMBOL(xfrm_policy_walk); 918EXPORT_SYMBOL(xfrm_policy_walk);
@@ -894,7 +934,8 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,
894 934
895 match = xfrm_selector_match(sel, fl, family); 935 match = xfrm_selector_match(sel, fl, family);
896 if (match) 936 if (match)
897 ret = security_xfrm_policy_lookup(pol, fl->secid, dir); 937 ret = security_xfrm_policy_lookup(pol->security, fl->secid,
938 dir);
898 939
899 return ret; 940 return ret;
900} 941}
@@ -1011,8 +1052,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc
1011 int err = 0; 1052 int err = 0;
1012 1053
1013 if (match) { 1054 if (match) {
1014 err = security_xfrm_policy_lookup(pol, fl->secid, 1055 err = security_xfrm_policy_lookup(pol->security,
1015 policy_to_flow_dir(dir)); 1056 fl->secid,
1057 policy_to_flow_dir(dir));
1016 if (!err) 1058 if (!err)
1017 xfrm_pol_hold(pol); 1059 xfrm_pol_hold(pol);
1018 else if (err == -ESRCH) 1060 else if (err == -ESRCH)
@@ -1101,7 +1143,8 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir)
1101 1143
1102 if (newp) { 1144 if (newp) {
1103 newp->selector = old->selector; 1145 newp->selector = old->selector;
1104 if (security_xfrm_policy_clone(old, newp)) { 1146 if (security_xfrm_policy_clone(old->security,
1147 &newp->security)) {
1105 kfree(newp); 1148 kfree(newp);
1106 return NULL; /* ENOMEM */ 1149 return NULL; /* ENOMEM */
1107 } 1150 }
@@ -1344,6 +1387,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1344 int trailer_len = 0; 1387 int trailer_len = 0;
1345 int tos; 1388 int tos;
1346 int family = policy->selector.family; 1389 int family = policy->selector.family;
1390 xfrm_address_t saddr, daddr;
1391
1392 xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
1347 1393
1348 tos = xfrm_get_tos(fl, family); 1394 tos = xfrm_get_tos(fl, family);
1349 err = tos; 1395 err = tos;
@@ -1374,7 +1420,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1374 1420
1375 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { 1421 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
1376 family = xfrm[i]->props.family; 1422 family = xfrm[i]->props.family;
1377 dst = xfrm_dst_lookup(xfrm[i], tos, family); 1423 dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr,
1424 family);
1378 err = PTR_ERR(dst); 1425 err = PTR_ERR(dst);
1379 if (IS_ERR(dst)) 1426 if (IS_ERR(dst))
1380 goto put_states; 1427 goto put_states;
@@ -2038,7 +2085,7 @@ static int stale_bundle(struct dst_entry *dst)
2038void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) 2085void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
2039{ 2086{
2040 while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { 2087 while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
2041 dst->dev = dev->nd_net->loopback_dev; 2088 dst->dev = dev_net(dev)->loopback_dev;
2042 dev_hold(dst->dev); 2089 dev_hold(dst->dev);
2043 dev_put(dev); 2090 dev_put(dev);
2044 } 2091 }
@@ -2309,7 +2356,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
2309{ 2356{
2310 struct net_device *dev = ptr; 2357 struct net_device *dev = ptr;
2311 2358
2312 if (dev->nd_net != &init_net) 2359 if (dev_net(dev) != &init_net)
2313 return NOTIFY_DONE; 2360 return NOTIFY_DONE;
2314 2361
2315 switch (event) { 2362 switch (event) {
@@ -2365,6 +2412,9 @@ static void __init xfrm_policy_init(void)
2365 panic("XFRM: failed to allocate bydst hash\n"); 2412 panic("XFRM: failed to allocate bydst hash\n");
2366 } 2413 }
2367 2414
2415 for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
2416 INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
2417
2368 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); 2418 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
2369 register_netdevice_notifier(&xfrm_dev_notifier); 2419 register_netdevice_notifier(&xfrm_dev_notifier);
2370} 2420}