diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 156 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 53 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 104 |
3 files changed, 199 insertions, 114 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 | ||
47 | static DEFINE_RWLOCK(xfrm_policy_lock); | 47 | static DEFINE_RWLOCK(xfrm_policy_lock); |
48 | 48 | ||
49 | static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX]; | ||
49 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; | 50 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; |
50 | EXPORT_SYMBOL(xfrm_policy_count); | 51 | EXPORT_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 | ||
100 | static 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 | |||
99 | static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, | 119 | static 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 | } |
236 | EXPORT_SYMBOL(xfrm_policy_destroy); | 269 | EXPORT_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 | } |
823 | EXPORT_SYMBOL(xfrm_policy_flush); | 860 | EXPORT_SYMBOL(xfrm_policy_flush); |
824 | 861 | ||
825 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), | 862 | int 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); | ||
874 | out: | 912 | out: |
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 | } |
878 | EXPORT_SYMBOL(xfrm_policy_walk); | 918 | EXPORT_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) | |||
2038 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) | 2085 | void 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 | } |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 58f1f9347b54..5dcc10b93c86 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -50,6 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock); | |||
50 | * Main use is finding SA after policy selected tunnel or transport mode. | 50 | * Main use is finding SA after policy selected tunnel or transport mode. |
51 | * Also, it can be used by ah/esp icmp error handler to find offending SA. | 51 | * Also, it can be used by ah/esp icmp error handler to find offending SA. |
52 | */ | 52 | */ |
53 | static LIST_HEAD(xfrm_state_all); | ||
53 | static struct hlist_head *xfrm_state_bydst __read_mostly; | 54 | static struct hlist_head *xfrm_state_bydst __read_mostly; |
54 | static struct hlist_head *xfrm_state_bysrc __read_mostly; | 55 | static struct hlist_head *xfrm_state_bysrc __read_mostly; |
55 | static struct hlist_head *xfrm_state_byspi __read_mostly; | 56 | static struct hlist_head *xfrm_state_byspi __read_mostly; |
@@ -512,6 +513,7 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
512 | if (x) { | 513 | if (x) { |
513 | atomic_set(&x->refcnt, 1); | 514 | atomic_set(&x->refcnt, 1); |
514 | atomic_set(&x->tunnel_users, 0); | 515 | atomic_set(&x->tunnel_users, 0); |
516 | INIT_LIST_HEAD(&x->all); | ||
515 | INIT_HLIST_NODE(&x->bydst); | 517 | INIT_HLIST_NODE(&x->bydst); |
516 | INIT_HLIST_NODE(&x->bysrc); | 518 | INIT_HLIST_NODE(&x->bysrc); |
517 | INIT_HLIST_NODE(&x->byspi); | 519 | INIT_HLIST_NODE(&x->byspi); |
@@ -537,6 +539,10 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
537 | { | 539 | { |
538 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); | 540 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); |
539 | 541 | ||
542 | spin_lock_bh(&xfrm_state_lock); | ||
543 | list_del(&x->all); | ||
544 | spin_unlock_bh(&xfrm_state_lock); | ||
545 | |||
540 | spin_lock_bh(&xfrm_state_gc_lock); | 546 | spin_lock_bh(&xfrm_state_gc_lock); |
541 | hlist_add_head(&x->bydst, &xfrm_state_gc_list); | 547 | hlist_add_head(&x->bydst, &xfrm_state_gc_list); |
542 | spin_unlock_bh(&xfrm_state_gc_lock); | 548 | spin_unlock_bh(&xfrm_state_gc_lock); |
@@ -913,6 +919,8 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
913 | 919 | ||
914 | x->genid = ++xfrm_state_genid; | 920 | x->genid = ++xfrm_state_genid; |
915 | 921 | ||
922 | list_add_tail(&x->all, &xfrm_state_all); | ||
923 | |||
916 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, | 924 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, |
917 | x->props.reqid, x->props.family); | 925 | x->props.reqid, x->props.family); |
918 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | 926 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
@@ -1522,36 +1530,47 @@ unlock: | |||
1522 | } | 1530 | } |
1523 | EXPORT_SYMBOL(xfrm_alloc_spi); | 1531 | EXPORT_SYMBOL(xfrm_alloc_spi); |
1524 | 1532 | ||
1525 | int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), | 1533 | int xfrm_state_walk(struct xfrm_state_walk *walk, |
1534 | int (*func)(struct xfrm_state *, int, void*), | ||
1526 | void *data) | 1535 | void *data) |
1527 | { | 1536 | { |
1528 | int i; | 1537 | struct xfrm_state *old, *x, *last = NULL; |
1529 | struct xfrm_state *x, *last = NULL; | ||
1530 | struct hlist_node *entry; | ||
1531 | int count = 0; | ||
1532 | int err = 0; | 1538 | int err = 0; |
1533 | 1539 | ||
1540 | if (walk->state == NULL && walk->count != 0) | ||
1541 | return 0; | ||
1542 | |||
1543 | old = x = walk->state; | ||
1544 | walk->state = NULL; | ||
1534 | spin_lock_bh(&xfrm_state_lock); | 1545 | spin_lock_bh(&xfrm_state_lock); |
1535 | for (i = 0; i <= xfrm_state_hmask; i++) { | 1546 | if (x == NULL) |
1536 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { | 1547 | x = list_first_entry(&xfrm_state_all, struct xfrm_state, all); |
1537 | if (!xfrm_id_proto_match(x->id.proto, proto)) | 1548 | list_for_each_entry_from(x, &xfrm_state_all, all) { |
1538 | continue; | 1549 | if (x->km.state == XFRM_STATE_DEAD) |
1539 | if (last) { | 1550 | continue; |
1540 | err = func(last, count, data); | 1551 | if (!xfrm_id_proto_match(x->id.proto, walk->proto)) |
1541 | if (err) | 1552 | continue; |
1542 | goto out; | 1553 | if (last) { |
1554 | err = func(last, walk->count, data); | ||
1555 | if (err) { | ||
1556 | xfrm_state_hold(last); | ||
1557 | walk->state = last; | ||
1558 | goto out; | ||
1543 | } | 1559 | } |
1544 | last = x; | ||
1545 | count++; | ||
1546 | } | 1560 | } |
1561 | last = x; | ||
1562 | walk->count++; | ||
1547 | } | 1563 | } |
1548 | if (count == 0) { | 1564 | if (walk->count == 0) { |
1549 | err = -ENOENT; | 1565 | err = -ENOENT; |
1550 | goto out; | 1566 | goto out; |
1551 | } | 1567 | } |
1552 | err = func(last, 0, data); | 1568 | if (last) |
1569 | err = func(last, 0, data); | ||
1553 | out: | 1570 | out: |
1554 | spin_unlock_bh(&xfrm_state_lock); | 1571 | spin_unlock_bh(&xfrm_state_lock); |
1572 | if (old != NULL) | ||
1573 | xfrm_state_put(old); | ||
1555 | return err; | 1574 | return err; |
1556 | } | 1575 | } |
1557 | EXPORT_SYMBOL(xfrm_state_walk); | 1576 | EXPORT_SYMBOL(xfrm_state_walk); |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 019d21de19b3..b822b56e5b8e 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -529,8 +529,6 @@ struct xfrm_dump_info { | |||
529 | struct sk_buff *out_skb; | 529 | struct sk_buff *out_skb; |
530 | u32 nlmsg_seq; | 530 | u32 nlmsg_seq; |
531 | u16 nlmsg_flags; | 531 | u16 nlmsg_flags; |
532 | int start_idx; | ||
533 | int this_idx; | ||
534 | }; | 532 | }; |
535 | 533 | ||
536 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) | 534 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) |
@@ -597,9 +595,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
597 | struct nlmsghdr *nlh; | 595 | struct nlmsghdr *nlh; |
598 | int err; | 596 | int err; |
599 | 597 | ||
600 | if (sp->this_idx < sp->start_idx) | ||
601 | goto out; | ||
602 | |||
603 | nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, | 598 | nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, |
604 | XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); | 599 | XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); |
605 | if (nlh == NULL) | 600 | if (nlh == NULL) |
@@ -612,8 +607,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
612 | goto nla_put_failure; | 607 | goto nla_put_failure; |
613 | 608 | ||
614 | nlmsg_end(skb, nlh); | 609 | nlmsg_end(skb, nlh); |
615 | out: | ||
616 | sp->this_idx++; | ||
617 | return 0; | 610 | return 0; |
618 | 611 | ||
619 | nla_put_failure: | 612 | nla_put_failure: |
@@ -621,18 +614,32 @@ nla_put_failure: | |||
621 | return err; | 614 | return err; |
622 | } | 615 | } |
623 | 616 | ||
617 | static int xfrm_dump_sa_done(struct netlink_callback *cb) | ||
618 | { | ||
619 | struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; | ||
620 | xfrm_state_walk_done(walk); | ||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | 624 | static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) |
625 | { | 625 | { |
626 | struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; | ||
626 | struct xfrm_dump_info info; | 627 | struct xfrm_dump_info info; |
627 | 628 | ||
629 | BUILD_BUG_ON(sizeof(struct xfrm_state_walk) > | ||
630 | sizeof(cb->args) - sizeof(cb->args[0])); | ||
631 | |||
628 | info.in_skb = cb->skb; | 632 | info.in_skb = cb->skb; |
629 | info.out_skb = skb; | 633 | info.out_skb = skb; |
630 | info.nlmsg_seq = cb->nlh->nlmsg_seq; | 634 | info.nlmsg_seq = cb->nlh->nlmsg_seq; |
631 | info.nlmsg_flags = NLM_F_MULTI; | 635 | info.nlmsg_flags = NLM_F_MULTI; |
632 | info.this_idx = 0; | 636 | |
633 | info.start_idx = cb->args[0]; | 637 | if (!cb->args[0]) { |
634 | (void) xfrm_state_walk(0, dump_one_state, &info); | 638 | cb->args[0] = 1; |
635 | cb->args[0] = info.this_idx; | 639 | xfrm_state_walk_init(walk, 0); |
640 | } | ||
641 | |||
642 | (void) xfrm_state_walk(walk, dump_one_state, &info); | ||
636 | 643 | ||
637 | return skb->len; | 644 | return skb->len; |
638 | } | 645 | } |
@@ -651,7 +658,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, | |||
651 | info.out_skb = skb; | 658 | info.out_skb = skb; |
652 | info.nlmsg_seq = seq; | 659 | info.nlmsg_seq = seq; |
653 | info.nlmsg_flags = 0; | 660 | info.nlmsg_flags = 0; |
654 | info.this_idx = info.start_idx = 0; | ||
655 | 661 | ||
656 | if (dump_one_state(x, 0, &info)) { | 662 | if (dump_one_state(x, 0, &info)) { |
657 | kfree_skb(skb); | 663 | kfree_skb(skb); |
@@ -953,7 +959,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs | |||
953 | return 0; | 959 | return 0; |
954 | 960 | ||
955 | uctx = nla_data(rt); | 961 | uctx = nla_data(rt); |
956 | return security_xfrm_policy_alloc(pol, uctx); | 962 | return security_xfrm_policy_alloc(&pol->security, uctx); |
957 | } | 963 | } |
958 | 964 | ||
959 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | 965 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, |
@@ -1137,7 +1143,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1137 | NETLINK_CB(skb).sid); | 1143 | NETLINK_CB(skb).sid); |
1138 | 1144 | ||
1139 | if (err) { | 1145 | if (err) { |
1140 | security_xfrm_policy_free(xp); | 1146 | security_xfrm_policy_free(xp->security); |
1141 | kfree(xp); | 1147 | kfree(xp); |
1142 | return err; | 1148 | return err; |
1143 | } | 1149 | } |
@@ -1229,9 +1235,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
1229 | struct sk_buff *skb = sp->out_skb; | 1235 | struct sk_buff *skb = sp->out_skb; |
1230 | struct nlmsghdr *nlh; | 1236 | struct nlmsghdr *nlh; |
1231 | 1237 | ||
1232 | if (sp->this_idx < sp->start_idx) | ||
1233 | goto out; | ||
1234 | |||
1235 | nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, | 1238 | nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, |
1236 | XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); | 1239 | XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); |
1237 | if (nlh == NULL) | 1240 | if (nlh == NULL) |
@@ -1247,8 +1250,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
1247 | goto nlmsg_failure; | 1250 | goto nlmsg_failure; |
1248 | 1251 | ||
1249 | nlmsg_end(skb, nlh); | 1252 | nlmsg_end(skb, nlh); |
1250 | out: | ||
1251 | sp->this_idx++; | ||
1252 | return 0; | 1253 | return 0; |
1253 | 1254 | ||
1254 | nlmsg_failure: | 1255 | nlmsg_failure: |
@@ -1256,21 +1257,33 @@ nlmsg_failure: | |||
1256 | return -EMSGSIZE; | 1257 | return -EMSGSIZE; |
1257 | } | 1258 | } |
1258 | 1259 | ||
1260 | static int xfrm_dump_policy_done(struct netlink_callback *cb) | ||
1261 | { | ||
1262 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; | ||
1263 | |||
1264 | xfrm_policy_walk_done(walk); | ||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1259 | static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | 1268 | static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) |
1260 | { | 1269 | { |
1270 | struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; | ||
1261 | struct xfrm_dump_info info; | 1271 | struct xfrm_dump_info info; |
1262 | 1272 | ||
1273 | BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > | ||
1274 | sizeof(cb->args) - sizeof(cb->args[0])); | ||
1275 | |||
1263 | info.in_skb = cb->skb; | 1276 | info.in_skb = cb->skb; |
1264 | info.out_skb = skb; | 1277 | info.out_skb = skb; |
1265 | info.nlmsg_seq = cb->nlh->nlmsg_seq; | 1278 | info.nlmsg_seq = cb->nlh->nlmsg_seq; |
1266 | info.nlmsg_flags = NLM_F_MULTI; | 1279 | info.nlmsg_flags = NLM_F_MULTI; |
1267 | info.this_idx = 0; | 1280 | |
1268 | info.start_idx = cb->args[0]; | 1281 | if (!cb->args[0]) { |
1269 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); | 1282 | cb->args[0] = 1; |
1270 | #ifdef CONFIG_XFRM_SUB_POLICY | 1283 | xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); |
1271 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); | 1284 | } |
1272 | #endif | 1285 | |
1273 | cb->args[0] = info.this_idx; | 1286 | (void) xfrm_policy_walk(walk, dump_one_policy, &info); |
1274 | 1287 | ||
1275 | return skb->len; | 1288 | return skb->len; |
1276 | } | 1289 | } |
@@ -1290,7 +1303,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, | |||
1290 | info.out_skb = skb; | 1303 | info.out_skb = skb; |
1291 | info.nlmsg_seq = seq; | 1304 | info.nlmsg_seq = seq; |
1292 | info.nlmsg_flags = 0; | 1305 | info.nlmsg_flags = 0; |
1293 | info.this_idx = info.start_idx = 0; | ||
1294 | 1306 | ||
1295 | if (dump_one_policy(xp, dir, 0, &info) < 0) { | 1307 | if (dump_one_policy(xp, dir, 0, &info) < 0) { |
1296 | kfree_skb(skb); | 1308 | kfree_skb(skb); |
@@ -1325,22 +1337,23 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1325 | xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); | 1337 | xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); |
1326 | else { | 1338 | else { |
1327 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 1339 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
1328 | struct xfrm_policy tmp; | 1340 | struct xfrm_sec_ctx *ctx; |
1329 | 1341 | ||
1330 | err = verify_sec_ctx_len(attrs); | 1342 | err = verify_sec_ctx_len(attrs); |
1331 | if (err) | 1343 | if (err) |
1332 | return err; | 1344 | return err; |
1333 | 1345 | ||
1334 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
1335 | if (rt) { | 1346 | if (rt) { |
1336 | struct xfrm_user_sec_ctx *uctx = nla_data(rt); | 1347 | struct xfrm_user_sec_ctx *uctx = nla_data(rt); |
1337 | 1348 | ||
1338 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1349 | err = security_xfrm_policy_alloc(&ctx, uctx); |
1350 | if (err) | ||
1339 | return err; | 1351 | return err; |
1340 | } | 1352 | } else |
1341 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, | 1353 | ctx = NULL; |
1354 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, | ||
1342 | delete, &err); | 1355 | delete, &err); |
1343 | security_xfrm_policy_free(&tmp); | 1356 | security_xfrm_policy_free(ctx); |
1344 | } | 1357 | } |
1345 | if (xp == NULL) | 1358 | if (xp == NULL) |
1346 | return -ENOENT; | 1359 | return -ENOENT; |
@@ -1560,26 +1573,26 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1560 | xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); | 1573 | xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); |
1561 | else { | 1574 | else { |
1562 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 1575 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
1563 | struct xfrm_policy tmp; | 1576 | struct xfrm_sec_ctx *ctx; |
1564 | 1577 | ||
1565 | err = verify_sec_ctx_len(attrs); | 1578 | err = verify_sec_ctx_len(attrs); |
1566 | if (err) | 1579 | if (err) |
1567 | return err; | 1580 | return err; |
1568 | 1581 | ||
1569 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
1570 | if (rt) { | 1582 | if (rt) { |
1571 | struct xfrm_user_sec_ctx *uctx = nla_data(rt); | 1583 | struct xfrm_user_sec_ctx *uctx = nla_data(rt); |
1572 | 1584 | ||
1573 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1585 | err = security_xfrm_policy_alloc(&ctx, uctx); |
1586 | if (err) | ||
1574 | return err; | 1587 | return err; |
1575 | } | 1588 | } else |
1576 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, | 1589 | ctx = NULL; |
1577 | 0, &err); | 1590 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, 0, &err); |
1578 | security_xfrm_policy_free(&tmp); | 1591 | security_xfrm_policy_free(ctx); |
1579 | } | 1592 | } |
1580 | |||
1581 | if (xp == NULL) | 1593 | if (xp == NULL) |
1582 | return -ENOENT; | 1594 | return -ENOENT; |
1595 | |||
1583 | read_lock(&xp->lock); | 1596 | read_lock(&xp->lock); |
1584 | if (xp->dead) { | 1597 | if (xp->dead) { |
1585 | read_unlock(&xp->lock); | 1598 | read_unlock(&xp->lock); |
@@ -1888,15 +1901,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
1888 | static struct xfrm_link { | 1901 | static struct xfrm_link { |
1889 | int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); | 1902 | int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); |
1890 | int (*dump)(struct sk_buff *, struct netlink_callback *); | 1903 | int (*dump)(struct sk_buff *, struct netlink_callback *); |
1904 | int (*done)(struct netlink_callback *); | ||
1891 | } xfrm_dispatch[XFRM_NR_MSGTYPES] = { | 1905 | } xfrm_dispatch[XFRM_NR_MSGTYPES] = { |
1892 | [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, | 1906 | [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, |
1893 | [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, | 1907 | [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, |
1894 | [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, | 1908 | [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, |
1895 | .dump = xfrm_dump_sa }, | 1909 | .dump = xfrm_dump_sa, |
1910 | .done = xfrm_dump_sa_done }, | ||
1896 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, | 1911 | [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, |
1897 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, | 1912 | [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, |
1898 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, | 1913 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, |
1899 | .dump = xfrm_dump_policy }, | 1914 | .dump = xfrm_dump_policy, |
1915 | .done = xfrm_dump_policy_done }, | ||
1900 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, | 1916 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, |
1901 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, | 1917 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, |
1902 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, | 1918 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, |
@@ -1935,7 +1951,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1935 | if (link->dump == NULL) | 1951 | if (link->dump == NULL) |
1936 | return -EINVAL; | 1952 | return -EINVAL; |
1937 | 1953 | ||
1938 | return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); | 1954 | return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done); |
1939 | } | 1955 | } |
1940 | 1956 | ||
1941 | err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, | 1957 | err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, |