diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 272 |
1 files changed, 232 insertions, 40 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b95a2d64eb59..6106b72826d3 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -62,6 +62,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) | |||
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | static int verify_auth_trunc(struct nlattr **attrs) | ||
66 | { | ||
67 | struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC]; | ||
68 | struct xfrm_algo_auth *algp; | ||
69 | |||
70 | if (!rt) | ||
71 | return 0; | ||
72 | |||
73 | algp = nla_data(rt); | ||
74 | if (nla_len(rt) < xfrm_alg_auth_len(algp)) | ||
75 | return -EINVAL; | ||
76 | |||
77 | algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; | ||
78 | return 0; | ||
79 | } | ||
80 | |||
65 | static int verify_aead(struct nlattr **attrs) | 81 | static int verify_aead(struct nlattr **attrs) |
66 | { | 82 | { |
67 | struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; | 83 | struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; |
@@ -128,7 +144,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
128 | err = -EINVAL; | 144 | err = -EINVAL; |
129 | switch (p->id.proto) { | 145 | switch (p->id.proto) { |
130 | case IPPROTO_AH: | 146 | case IPPROTO_AH: |
131 | if (!attrs[XFRMA_ALG_AUTH] || | 147 | if ((!attrs[XFRMA_ALG_AUTH] && |
148 | !attrs[XFRMA_ALG_AUTH_TRUNC]) || | ||
132 | attrs[XFRMA_ALG_AEAD] || | 149 | attrs[XFRMA_ALG_AEAD] || |
133 | attrs[XFRMA_ALG_CRYPT] || | 150 | attrs[XFRMA_ALG_CRYPT] || |
134 | attrs[XFRMA_ALG_COMP]) | 151 | attrs[XFRMA_ALG_COMP]) |
@@ -139,10 +156,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
139 | if (attrs[XFRMA_ALG_COMP]) | 156 | if (attrs[XFRMA_ALG_COMP]) |
140 | goto out; | 157 | goto out; |
141 | if (!attrs[XFRMA_ALG_AUTH] && | 158 | if (!attrs[XFRMA_ALG_AUTH] && |
159 | !attrs[XFRMA_ALG_AUTH_TRUNC] && | ||
142 | !attrs[XFRMA_ALG_CRYPT] && | 160 | !attrs[XFRMA_ALG_CRYPT] && |
143 | !attrs[XFRMA_ALG_AEAD]) | 161 | !attrs[XFRMA_ALG_AEAD]) |
144 | goto out; | 162 | goto out; |
145 | if ((attrs[XFRMA_ALG_AUTH] || | 163 | if ((attrs[XFRMA_ALG_AUTH] || |
164 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
146 | attrs[XFRMA_ALG_CRYPT]) && | 165 | attrs[XFRMA_ALG_CRYPT]) && |
147 | attrs[XFRMA_ALG_AEAD]) | 166 | attrs[XFRMA_ALG_AEAD]) |
148 | goto out; | 167 | goto out; |
@@ -152,6 +171,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
152 | if (!attrs[XFRMA_ALG_COMP] || | 171 | if (!attrs[XFRMA_ALG_COMP] || |
153 | attrs[XFRMA_ALG_AEAD] || | 172 | attrs[XFRMA_ALG_AEAD] || |
154 | attrs[XFRMA_ALG_AUTH] || | 173 | attrs[XFRMA_ALG_AUTH] || |
174 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
155 | attrs[XFRMA_ALG_CRYPT]) | 175 | attrs[XFRMA_ALG_CRYPT]) |
156 | goto out; | 176 | goto out; |
157 | break; | 177 | break; |
@@ -161,6 +181,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
161 | case IPPROTO_ROUTING: | 181 | case IPPROTO_ROUTING: |
162 | if (attrs[XFRMA_ALG_COMP] || | 182 | if (attrs[XFRMA_ALG_COMP] || |
163 | attrs[XFRMA_ALG_AUTH] || | 183 | attrs[XFRMA_ALG_AUTH] || |
184 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
164 | attrs[XFRMA_ALG_AEAD] || | 185 | attrs[XFRMA_ALG_AEAD] || |
165 | attrs[XFRMA_ALG_CRYPT] || | 186 | attrs[XFRMA_ALG_CRYPT] || |
166 | attrs[XFRMA_ENCAP] || | 187 | attrs[XFRMA_ENCAP] || |
@@ -176,6 +197,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
176 | 197 | ||
177 | if ((err = verify_aead(attrs))) | 198 | if ((err = verify_aead(attrs))) |
178 | goto out; | 199 | goto out; |
200 | if ((err = verify_auth_trunc(attrs))) | ||
201 | goto out; | ||
179 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) | 202 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) |
180 | goto out; | 203 | goto out; |
181 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) | 204 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) |
@@ -229,6 +252,66 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, | |||
229 | return 0; | 252 | return 0; |
230 | } | 253 | } |
231 | 254 | ||
255 | static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props, | ||
256 | struct nlattr *rta) | ||
257 | { | ||
258 | struct xfrm_algo *ualg; | ||
259 | struct xfrm_algo_auth *p; | ||
260 | struct xfrm_algo_desc *algo; | ||
261 | |||
262 | if (!rta) | ||
263 | return 0; | ||
264 | |||
265 | ualg = nla_data(rta); | ||
266 | |||
267 | algo = xfrm_aalg_get_byname(ualg->alg_name, 1); | ||
268 | if (!algo) | ||
269 | return -ENOSYS; | ||
270 | *props = algo->desc.sadb_alg_id; | ||
271 | |||
272 | p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL); | ||
273 | if (!p) | ||
274 | return -ENOMEM; | ||
275 | |||
276 | strcpy(p->alg_name, algo->name); | ||
277 | p->alg_key_len = ualg->alg_key_len; | ||
278 | p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; | ||
279 | memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8); | ||
280 | |||
281 | *algpp = p; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props, | ||
286 | struct nlattr *rta) | ||
287 | { | ||
288 | struct xfrm_algo_auth *p, *ualg; | ||
289 | struct xfrm_algo_desc *algo; | ||
290 | |||
291 | if (!rta) | ||
292 | return 0; | ||
293 | |||
294 | ualg = nla_data(rta); | ||
295 | |||
296 | algo = xfrm_aalg_get_byname(ualg->alg_name, 1); | ||
297 | if (!algo) | ||
298 | return -ENOSYS; | ||
299 | if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits) | ||
300 | return -EINVAL; | ||
301 | *props = algo->desc.sadb_alg_id; | ||
302 | |||
303 | p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL); | ||
304 | if (!p) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | strcpy(p->alg_name, algo->name); | ||
308 | if (!p->alg_trunc_len) | ||
309 | p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; | ||
310 | |||
311 | *algpp = p; | ||
312 | return 0; | ||
313 | } | ||
314 | |||
232 | static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, | 315 | static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, |
233 | struct nlattr *rta) | 316 | struct nlattr *rta) |
234 | { | 317 | { |
@@ -332,10 +415,14 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
332 | if ((err = attach_aead(&x->aead, &x->props.ealgo, | 415 | if ((err = attach_aead(&x->aead, &x->props.ealgo, |
333 | attrs[XFRMA_ALG_AEAD]))) | 416 | attrs[XFRMA_ALG_AEAD]))) |
334 | goto error; | 417 | goto error; |
335 | if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, | 418 | if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo, |
336 | xfrm_aalg_get_byname, | 419 | attrs[XFRMA_ALG_AUTH_TRUNC]))) |
337 | attrs[XFRMA_ALG_AUTH]))) | ||
338 | goto error; | 420 | goto error; |
421 | if (!x->props.aalgo) { | ||
422 | if ((err = attach_auth(&x->aalg, &x->props.aalgo, | ||
423 | attrs[XFRMA_ALG_AUTH]))) | ||
424 | goto error; | ||
425 | } | ||
339 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, | 426 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, |
340 | xfrm_ealg_get_byname, | 427 | xfrm_ealg_get_byname, |
341 | attrs[XFRMA_ALG_CRYPT]))) | 428 | attrs[XFRMA_ALG_CRYPT]))) |
@@ -359,6 +446,8 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
359 | goto error; | 446 | goto error; |
360 | } | 447 | } |
361 | 448 | ||
449 | xfrm_mark_get(attrs, &x->mark); | ||
450 | |||
362 | err = xfrm_init_state(x); | 451 | err = xfrm_init_state(x); |
363 | if (err) | 452 | if (err) |
364 | goto error; | 453 | goto error; |
@@ -439,11 +528,13 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net, | |||
439 | int *errp) | 528 | int *errp) |
440 | { | 529 | { |
441 | struct xfrm_state *x = NULL; | 530 | struct xfrm_state *x = NULL; |
531 | struct xfrm_mark m; | ||
442 | int err; | 532 | int err; |
533 | u32 mark = xfrm_mark_get(attrs, &m); | ||
443 | 534 | ||
444 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | 535 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { |
445 | err = -ESRCH; | 536 | err = -ESRCH; |
446 | x = xfrm_state_lookup(net, &p->daddr, p->spi, p->proto, p->family); | 537 | x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family); |
447 | } else { | 538 | } else { |
448 | xfrm_address_t *saddr = NULL; | 539 | xfrm_address_t *saddr = NULL; |
449 | 540 | ||
@@ -454,7 +545,8 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net, | |||
454 | } | 545 | } |
455 | 546 | ||
456 | err = -ESRCH; | 547 | err = -ESRCH; |
457 | x = xfrm_state_lookup_byaddr(net, &p->daddr, saddr, | 548 | x = xfrm_state_lookup_byaddr(net, mark, |
549 | &p->daddr, saddr, | ||
458 | p->proto, p->family); | 550 | p->proto, p->family); |
459 | } | 551 | } |
460 | 552 | ||
@@ -548,6 +640,24 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) | |||
548 | return 0; | 640 | return 0; |
549 | } | 641 | } |
550 | 642 | ||
643 | static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb) | ||
644 | { | ||
645 | struct xfrm_algo *algo; | ||
646 | struct nlattr *nla; | ||
647 | |||
648 | nla = nla_reserve(skb, XFRMA_ALG_AUTH, | ||
649 | sizeof(*algo) + (auth->alg_key_len + 7) / 8); | ||
650 | if (!nla) | ||
651 | return -EMSGSIZE; | ||
652 | |||
653 | algo = nla_data(nla); | ||
654 | strcpy(algo->alg_name, auth->alg_name); | ||
655 | memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8); | ||
656 | algo->alg_key_len = auth->alg_key_len; | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
551 | /* Don't change this without updating xfrm_sa_len! */ | 661 | /* Don't change this without updating xfrm_sa_len! */ |
552 | static int copy_to_user_state_extra(struct xfrm_state *x, | 662 | static int copy_to_user_state_extra(struct xfrm_state *x, |
553 | struct xfrm_usersa_info *p, | 663 | struct xfrm_usersa_info *p, |
@@ -563,8 +673,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
563 | 673 | ||
564 | if (x->aead) | 674 | if (x->aead) |
565 | NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); | 675 | NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); |
566 | if (x->aalg) | 676 | if (x->aalg) { |
567 | NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); | 677 | if (copy_to_user_auth(x->aalg, skb)) |
678 | goto nla_put_failure; | ||
679 | |||
680 | NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC, | ||
681 | xfrm_alg_auth_len(x->aalg), x->aalg); | ||
682 | } | ||
568 | if (x->ealg) | 683 | if (x->ealg) |
569 | NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); | 684 | NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); |
570 | if (x->calg) | 685 | if (x->calg) |
@@ -573,6 +688,9 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
573 | if (x->encap) | 688 | if (x->encap) |
574 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 689 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
575 | 690 | ||
691 | if (xfrm_mark_put(skb, &x->mark)) | ||
692 | goto nla_put_failure; | ||
693 | |||
576 | if (x->security && copy_sec_ctx(x->security, skb) < 0) | 694 | if (x->security && copy_sec_ctx(x->security, skb) < 0) |
577 | goto nla_put_failure; | 695 | goto nla_put_failure; |
578 | 696 | ||
@@ -671,7 +789,8 @@ static inline size_t xfrm_spdinfo_msgsize(void) | |||
671 | + nla_total_size(sizeof(struct xfrmu_spdhinfo)); | 789 | + nla_total_size(sizeof(struct xfrmu_spdhinfo)); |
672 | } | 790 | } |
673 | 791 | ||
674 | static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | 792 | static int build_spdinfo(struct sk_buff *skb, struct net *net, |
793 | u32 pid, u32 seq, u32 flags) | ||
675 | { | 794 | { |
676 | struct xfrmk_spdinfo si; | 795 | struct xfrmk_spdinfo si; |
677 | struct xfrmu_spdinfo spc; | 796 | struct xfrmu_spdinfo spc; |
@@ -685,7 +804,7 @@ static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | |||
685 | 804 | ||
686 | f = nlmsg_data(nlh); | 805 | f = nlmsg_data(nlh); |
687 | *f = flags; | 806 | *f = flags; |
688 | xfrm_spd_getinfo(&si); | 807 | xfrm_spd_getinfo(net, &si); |
689 | spc.incnt = si.incnt; | 808 | spc.incnt = si.incnt; |
690 | spc.outcnt = si.outcnt; | 809 | spc.outcnt = si.outcnt; |
691 | spc.fwdcnt = si.fwdcnt; | 810 | spc.fwdcnt = si.fwdcnt; |
@@ -718,7 +837,7 @@ static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
718 | if (r_skb == NULL) | 837 | if (r_skb == NULL) |
719 | return -ENOMEM; | 838 | return -ENOMEM; |
720 | 839 | ||
721 | if (build_spdinfo(r_skb, spid, seq, *flags) < 0) | 840 | if (build_spdinfo(r_skb, net, spid, seq, *flags) < 0) |
722 | BUG(); | 841 | BUG(); |
723 | 842 | ||
724 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); | 843 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); |
@@ -731,7 +850,8 @@ static inline size_t xfrm_sadinfo_msgsize(void) | |||
731 | + nla_total_size(4); /* XFRMA_SAD_CNT */ | 850 | + nla_total_size(4); /* XFRMA_SAD_CNT */ |
732 | } | 851 | } |
733 | 852 | ||
734 | static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | 853 | static int build_sadinfo(struct sk_buff *skb, struct net *net, |
854 | u32 pid, u32 seq, u32 flags) | ||
735 | { | 855 | { |
736 | struct xfrmk_sadinfo si; | 856 | struct xfrmk_sadinfo si; |
737 | struct xfrmu_sadhinfo sh; | 857 | struct xfrmu_sadhinfo sh; |
@@ -744,7 +864,7 @@ static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | |||
744 | 864 | ||
745 | f = nlmsg_data(nlh); | 865 | f = nlmsg_data(nlh); |
746 | *f = flags; | 866 | *f = flags; |
747 | xfrm_sad_getinfo(&si); | 867 | xfrm_sad_getinfo(net, &si); |
748 | 868 | ||
749 | sh.sadhmcnt = si.sadhmcnt; | 869 | sh.sadhmcnt = si.sadhmcnt; |
750 | sh.sadhcnt = si.sadhcnt; | 870 | sh.sadhcnt = si.sadhcnt; |
@@ -772,7 +892,7 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
772 | if (r_skb == NULL) | 892 | if (r_skb == NULL) |
773 | return -ENOMEM; | 893 | return -ENOMEM; |
774 | 894 | ||
775 | if (build_sadinfo(r_skb, spid, seq, *flags) < 0) | 895 | if (build_sadinfo(r_skb, net, spid, seq, *flags) < 0) |
776 | BUG(); | 896 | BUG(); |
777 | 897 | ||
778 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); | 898 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); |
@@ -835,6 +955,8 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
835 | xfrm_address_t *daddr; | 955 | xfrm_address_t *daddr; |
836 | int family; | 956 | int family; |
837 | int err; | 957 | int err; |
958 | u32 mark; | ||
959 | struct xfrm_mark m; | ||
838 | 960 | ||
839 | p = nlmsg_data(nlh); | 961 | p = nlmsg_data(nlh); |
840 | err = verify_userspi_info(p); | 962 | err = verify_userspi_info(p); |
@@ -845,8 +967,10 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
845 | daddr = &p->info.id.daddr; | 967 | daddr = &p->info.id.daddr; |
846 | 968 | ||
847 | x = NULL; | 969 | x = NULL; |
970 | |||
971 | mark = xfrm_mark_get(attrs, &m); | ||
848 | if (p->info.seq) { | 972 | if (p->info.seq) { |
849 | x = xfrm_find_acq_byseq(net, p->info.seq); | 973 | x = xfrm_find_acq_byseq(net, mark, p->info.seq); |
850 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { | 974 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { |
851 | xfrm_state_put(x); | 975 | xfrm_state_put(x); |
852 | x = NULL; | 976 | x = NULL; |
@@ -854,7 +978,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
854 | } | 978 | } |
855 | 979 | ||
856 | if (!x) | 980 | if (!x) |
857 | x = xfrm_find_acq(net, p->info.mode, p->info.reqid, | 981 | x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, |
858 | p->info.id.proto, daddr, | 982 | p->info.id.proto, daddr, |
859 | &p->info.saddr, 1, | 983 | &p->info.saddr, 1, |
860 | family); | 984 | family); |
@@ -1108,6 +1232,8 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us | |||
1108 | if (err) | 1232 | if (err) |
1109 | goto error; | 1233 | goto error; |
1110 | 1234 | ||
1235 | xfrm_mark_get(attrs, &xp->mark); | ||
1236 | |||
1111 | return xp; | 1237 | return xp; |
1112 | error: | 1238 | error: |
1113 | *errp = err; | 1239 | *errp = err; |
@@ -1254,10 +1380,13 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
1254 | goto nlmsg_failure; | 1380 | goto nlmsg_failure; |
1255 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 1381 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
1256 | goto nlmsg_failure; | 1382 | goto nlmsg_failure; |
1383 | if (xfrm_mark_put(skb, &xp->mark)) | ||
1384 | goto nla_put_failure; | ||
1257 | 1385 | ||
1258 | nlmsg_end(skb, nlh); | 1386 | nlmsg_end(skb, nlh); |
1259 | return 0; | 1387 | return 0; |
1260 | 1388 | ||
1389 | nla_put_failure: | ||
1261 | nlmsg_failure: | 1390 | nlmsg_failure: |
1262 | nlmsg_cancel(skb, nlh); | 1391 | nlmsg_cancel(skb, nlh); |
1263 | return -EMSGSIZE; | 1392 | return -EMSGSIZE; |
@@ -1329,6 +1458,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1329 | int err; | 1458 | int err; |
1330 | struct km_event c; | 1459 | struct km_event c; |
1331 | int delete; | 1460 | int delete; |
1461 | struct xfrm_mark m; | ||
1462 | u32 mark = xfrm_mark_get(attrs, &m); | ||
1332 | 1463 | ||
1333 | p = nlmsg_data(nlh); | 1464 | p = nlmsg_data(nlh); |
1334 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1465 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
@@ -1342,7 +1473,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1342 | return err; | 1473 | return err; |
1343 | 1474 | ||
1344 | if (p->index) | 1475 | if (p->index) |
1345 | xp = xfrm_policy_byid(net, type, p->dir, p->index, delete, &err); | 1476 | xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err); |
1346 | else { | 1477 | else { |
1347 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 1478 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
1348 | struct xfrm_sec_ctx *ctx; | 1479 | struct xfrm_sec_ctx *ctx; |
@@ -1359,8 +1490,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1359 | if (err) | 1490 | if (err) |
1360 | return err; | 1491 | return err; |
1361 | } | 1492 | } |
1362 | xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, | 1493 | xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel, |
1363 | delete, &err); | 1494 | ctx, delete, &err); |
1364 | security_xfrm_policy_free(ctx); | 1495 | security_xfrm_policy_free(ctx); |
1365 | } | 1496 | } |
1366 | if (xp == NULL) | 1497 | if (xp == NULL) |
@@ -1412,8 +1543,11 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1412 | audit_info.sessionid = NETLINK_CB(skb).sessionid; | 1543 | audit_info.sessionid = NETLINK_CB(skb).sessionid; |
1413 | audit_info.secid = NETLINK_CB(skb).sid; | 1544 | audit_info.secid = NETLINK_CB(skb).sid; |
1414 | err = xfrm_state_flush(net, p->proto, &audit_info); | 1545 | err = xfrm_state_flush(net, p->proto, &audit_info); |
1415 | if (err) | 1546 | if (err) { |
1547 | if (err == -ESRCH) /* empty table */ | ||
1548 | return 0; | ||
1416 | return err; | 1549 | return err; |
1550 | } | ||
1417 | c.data.proto = p->proto; | 1551 | c.data.proto = p->proto; |
1418 | c.event = nlh->nlmsg_type; | 1552 | c.event = nlh->nlmsg_type; |
1419 | c.seq = nlh->nlmsg_seq; | 1553 | c.seq = nlh->nlmsg_seq; |
@@ -1429,6 +1563,7 @@ static inline size_t xfrm_aevent_msgsize(void) | |||
1429 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) | 1563 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) |
1430 | + nla_total_size(sizeof(struct xfrm_replay_state)) | 1564 | + nla_total_size(sizeof(struct xfrm_replay_state)) |
1431 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) | 1565 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) |
1566 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
1432 | + nla_total_size(4) /* XFRM_AE_RTHR */ | 1567 | + nla_total_size(4) /* XFRM_AE_RTHR */ |
1433 | + nla_total_size(4); /* XFRM_AE_ETHR */ | 1568 | + nla_total_size(4); /* XFRM_AE_ETHR */ |
1434 | } | 1569 | } |
@@ -1461,6 +1596,9 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve | |||
1461 | NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, | 1596 | NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, |
1462 | x->replay_maxage * 10 / HZ); | 1597 | x->replay_maxage * 10 / HZ); |
1463 | 1598 | ||
1599 | if (xfrm_mark_put(skb, &x->mark)) | ||
1600 | goto nla_put_failure; | ||
1601 | |||
1464 | return nlmsg_end(skb, nlh); | 1602 | return nlmsg_end(skb, nlh); |
1465 | 1603 | ||
1466 | nla_put_failure: | 1604 | nla_put_failure: |
@@ -1476,6 +1614,8 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1476 | struct sk_buff *r_skb; | 1614 | struct sk_buff *r_skb; |
1477 | int err; | 1615 | int err; |
1478 | struct km_event c; | 1616 | struct km_event c; |
1617 | u32 mark; | ||
1618 | struct xfrm_mark m; | ||
1479 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1619 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1480 | struct xfrm_usersa_id *id = &p->sa_id; | 1620 | struct xfrm_usersa_id *id = &p->sa_id; |
1481 | 1621 | ||
@@ -1483,7 +1623,9 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1483 | if (r_skb == NULL) | 1623 | if (r_skb == NULL) |
1484 | return -ENOMEM; | 1624 | return -ENOMEM; |
1485 | 1625 | ||
1486 | x = xfrm_state_lookup(net, &id->daddr, id->spi, id->proto, id->family); | 1626 | mark = xfrm_mark_get(attrs, &m); |
1627 | |||
1628 | x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family); | ||
1487 | if (x == NULL) { | 1629 | if (x == NULL) { |
1488 | kfree_skb(r_skb); | 1630 | kfree_skb(r_skb); |
1489 | return -ESRCH; | 1631 | return -ESRCH; |
@@ -1514,6 +1656,8 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1514 | struct xfrm_state *x; | 1656 | struct xfrm_state *x; |
1515 | struct km_event c; | 1657 | struct km_event c; |
1516 | int err = - EINVAL; | 1658 | int err = - EINVAL; |
1659 | u32 mark = 0; | ||
1660 | struct xfrm_mark m; | ||
1517 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1661 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1518 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; | 1662 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; |
1519 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; | 1663 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; |
@@ -1525,7 +1669,9 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1525 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) | 1669 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) |
1526 | return err; | 1670 | return err; |
1527 | 1671 | ||
1528 | x = xfrm_state_lookup(net, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | 1672 | mark = xfrm_mark_get(attrs, &m); |
1673 | |||
1674 | x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | ||
1529 | if (x == NULL) | 1675 | if (x == NULL) |
1530 | return -ESRCH; | 1676 | return -ESRCH; |
1531 | 1677 | ||
@@ -1564,8 +1710,12 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1564 | audit_info.sessionid = NETLINK_CB(skb).sessionid; | 1710 | audit_info.sessionid = NETLINK_CB(skb).sessionid; |
1565 | audit_info.secid = NETLINK_CB(skb).sid; | 1711 | audit_info.secid = NETLINK_CB(skb).sid; |
1566 | err = xfrm_policy_flush(net, type, &audit_info); | 1712 | err = xfrm_policy_flush(net, type, &audit_info); |
1567 | if (err) | 1713 | if (err) { |
1714 | if (err == -ESRCH) /* empty table */ | ||
1715 | return 0; | ||
1568 | return err; | 1716 | return err; |
1717 | } | ||
1718 | |||
1569 | c.data.type = type; | 1719 | c.data.type = type; |
1570 | c.event = nlh->nlmsg_type; | 1720 | c.event = nlh->nlmsg_type; |
1571 | c.seq = nlh->nlmsg_seq; | 1721 | c.seq = nlh->nlmsg_seq; |
@@ -1584,13 +1734,15 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1584 | struct xfrm_userpolicy_info *p = &up->pol; | 1734 | struct xfrm_userpolicy_info *p = &up->pol; |
1585 | u8 type = XFRM_POLICY_TYPE_MAIN; | 1735 | u8 type = XFRM_POLICY_TYPE_MAIN; |
1586 | int err = -ENOENT; | 1736 | int err = -ENOENT; |
1737 | struct xfrm_mark m; | ||
1738 | u32 mark = xfrm_mark_get(attrs, &m); | ||
1587 | 1739 | ||
1588 | err = copy_from_user_policy_type(&type, attrs); | 1740 | err = copy_from_user_policy_type(&type, attrs); |
1589 | if (err) | 1741 | if (err) |
1590 | return err; | 1742 | return err; |
1591 | 1743 | ||
1592 | if (p->index) | 1744 | if (p->index) |
1593 | xp = xfrm_policy_byid(net, type, p->dir, p->index, 0, &err); | 1745 | xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err); |
1594 | else { | 1746 | else { |
1595 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 1747 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
1596 | struct xfrm_sec_ctx *ctx; | 1748 | struct xfrm_sec_ctx *ctx; |
@@ -1607,7 +1759,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1607 | if (err) | 1759 | if (err) |
1608 | return err; | 1760 | return err; |
1609 | } | 1761 | } |
1610 | xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, 0, &err); | 1762 | xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, |
1763 | &p->sel, ctx, 0, &err); | ||
1611 | security_xfrm_policy_free(ctx); | 1764 | security_xfrm_policy_free(ctx); |
1612 | } | 1765 | } |
1613 | if (xp == NULL) | 1766 | if (xp == NULL) |
@@ -1647,8 +1800,10 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1647 | int err; | 1800 | int err; |
1648 | struct xfrm_user_expire *ue = nlmsg_data(nlh); | 1801 | struct xfrm_user_expire *ue = nlmsg_data(nlh); |
1649 | struct xfrm_usersa_info *p = &ue->state; | 1802 | struct xfrm_usersa_info *p = &ue->state; |
1803 | struct xfrm_mark m; | ||
1804 | u32 mark = xfrm_mark_get(attrs, &m);; | ||
1650 | 1805 | ||
1651 | x = xfrm_state_lookup(net, &p->id.daddr, p->id.spi, p->id.proto, p->family); | 1806 | x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family); |
1652 | 1807 | ||
1653 | err = -ENOENT; | 1808 | err = -ENOENT; |
1654 | if (x == NULL) | 1809 | if (x == NULL) |
@@ -1682,6 +1837,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1682 | struct xfrm_user_tmpl *ut; | 1837 | struct xfrm_user_tmpl *ut; |
1683 | int i; | 1838 | int i; |
1684 | struct nlattr *rt = attrs[XFRMA_TMPL]; | 1839 | struct nlattr *rt = attrs[XFRMA_TMPL]; |
1840 | struct xfrm_mark mark; | ||
1685 | 1841 | ||
1686 | struct xfrm_user_acquire *ua = nlmsg_data(nlh); | 1842 | struct xfrm_user_acquire *ua = nlmsg_data(nlh); |
1687 | struct xfrm_state *x = xfrm_state_alloc(net); | 1843 | struct xfrm_state *x = xfrm_state_alloc(net); |
@@ -1690,6 +1846,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1690 | if (!x) | 1846 | if (!x) |
1691 | goto nomem; | 1847 | goto nomem; |
1692 | 1848 | ||
1849 | xfrm_mark_get(attrs, &mark); | ||
1850 | |||
1693 | err = verify_newpolicy_info(&ua->policy); | 1851 | err = verify_newpolicy_info(&ua->policy); |
1694 | if (err) | 1852 | if (err) |
1695 | goto bad_policy; | 1853 | goto bad_policy; |
@@ -1702,7 +1860,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1702 | memcpy(&x->id, &ua->id, sizeof(ua->id)); | 1860 | memcpy(&x->id, &ua->id, sizeof(ua->id)); |
1703 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); | 1861 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); |
1704 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); | 1862 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); |
1705 | 1863 | xp->mark.m = x->mark.m = mark.m; | |
1864 | xp->mark.v = x->mark.v = mark.v; | ||
1706 | ut = nla_data(rt); | 1865 | ut = nla_data(rt); |
1707 | /* extract the templates and for each call km_key */ | 1866 | /* extract the templates and for each call km_key */ |
1708 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { | 1867 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { |
@@ -1942,6 +2101,10 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1942 | #undef XMSGSIZE | 2101 | #undef XMSGSIZE |
1943 | 2102 | ||
1944 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | 2103 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { |
2104 | [XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)}, | ||
2105 | [XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)}, | ||
2106 | [XFRMA_LASTUSED] = { .type = NLA_U64}, | ||
2107 | [XFRMA_ALG_AUTH_TRUNC] = { .len = sizeof(struct xfrm_algo_auth)}, | ||
1945 | [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, | 2108 | [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, |
1946 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, | 2109 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, |
1947 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, | 2110 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, |
@@ -1958,6 +2121,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
1958 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, | 2121 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, |
1959 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, | 2122 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, |
1960 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, | 2123 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, |
2124 | [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, | ||
1961 | }; | 2125 | }; |
1962 | 2126 | ||
1963 | static struct xfrm_link { | 2127 | static struct xfrm_link { |
@@ -2037,7 +2201,8 @@ static void xfrm_netlink_rcv(struct sk_buff *skb) | |||
2037 | 2201 | ||
2038 | static inline size_t xfrm_expire_msgsize(void) | 2202 | static inline size_t xfrm_expire_msgsize(void) |
2039 | { | 2203 | { |
2040 | return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)); | 2204 | return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) |
2205 | + nla_total_size(sizeof(struct xfrm_mark)); | ||
2041 | } | 2206 | } |
2042 | 2207 | ||
2043 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | 2208 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
@@ -2053,7 +2218,13 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve | |||
2053 | copy_to_user_state(x, &ue->state); | 2218 | copy_to_user_state(x, &ue->state); |
2054 | ue->hard = (c->data.hard != 0) ? 1 : 0; | 2219 | ue->hard = (c->data.hard != 0) ? 1 : 0; |
2055 | 2220 | ||
2221 | if (xfrm_mark_put(skb, &x->mark)) | ||
2222 | goto nla_put_failure; | ||
2223 | |||
2056 | return nlmsg_end(skb, nlh); | 2224 | return nlmsg_end(skb, nlh); |
2225 | |||
2226 | nla_put_failure: | ||
2227 | return -EMSGSIZE; | ||
2057 | } | 2228 | } |
2058 | 2229 | ||
2059 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | 2230 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) |
@@ -2065,8 +2236,10 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | |||
2065 | if (skb == NULL) | 2236 | if (skb == NULL) |
2066 | return -ENOMEM; | 2237 | return -ENOMEM; |
2067 | 2238 | ||
2068 | if (build_expire(skb, x, c) < 0) | 2239 | if (build_expire(skb, x, c) < 0) { |
2069 | BUG(); | 2240 | kfree_skb(skb); |
2241 | return -EMSGSIZE; | ||
2242 | } | ||
2070 | 2243 | ||
2071 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 2244 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
2072 | } | 2245 | } |
@@ -2117,8 +2290,11 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) | |||
2117 | size_t l = 0; | 2290 | size_t l = 0; |
2118 | if (x->aead) | 2291 | if (x->aead) |
2119 | l += nla_total_size(aead_len(x->aead)); | 2292 | l += nla_total_size(aead_len(x->aead)); |
2120 | if (x->aalg) | 2293 | if (x->aalg) { |
2121 | l += nla_total_size(xfrm_alg_len(x->aalg)); | 2294 | l += nla_total_size(sizeof(struct xfrm_algo) + |
2295 | (x->aalg->alg_key_len + 7) / 8); | ||
2296 | l += nla_total_size(xfrm_alg_auth_len(x->aalg)); | ||
2297 | } | ||
2122 | if (x->ealg) | 2298 | if (x->ealg) |
2123 | l += nla_total_size(xfrm_alg_len(x->ealg)); | 2299 | l += nla_total_size(xfrm_alg_len(x->ealg)); |
2124 | if (x->calg) | 2300 | if (x->calg) |
@@ -2151,6 +2327,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) | |||
2151 | if (c->event == XFRM_MSG_DELSA) { | 2327 | if (c->event == XFRM_MSG_DELSA) { |
2152 | len += nla_total_size(headlen); | 2328 | len += nla_total_size(headlen); |
2153 | headlen = sizeof(*id); | 2329 | headlen = sizeof(*id); |
2330 | len += nla_total_size(sizeof(struct xfrm_mark)); | ||
2154 | } | 2331 | } |
2155 | len += NLMSG_ALIGN(headlen); | 2332 | len += NLMSG_ALIGN(headlen); |
2156 | 2333 | ||
@@ -2221,6 +2398,7 @@ static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x, | |||
2221 | { | 2398 | { |
2222 | return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) | 2399 | return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) |
2223 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) | 2400 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) |
2401 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
2224 | + nla_total_size(xfrm_user_sec_ctx_size(x->security)) | 2402 | + nla_total_size(xfrm_user_sec_ctx_size(x->security)) |
2225 | + userpolicy_type_attrsize(); | 2403 | + userpolicy_type_attrsize(); |
2226 | } | 2404 | } |
@@ -2253,9 +2431,12 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
2253 | goto nlmsg_failure; | 2431 | goto nlmsg_failure; |
2254 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2432 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2255 | goto nlmsg_failure; | 2433 | goto nlmsg_failure; |
2434 | if (xfrm_mark_put(skb, &xp->mark)) | ||
2435 | goto nla_put_failure; | ||
2256 | 2436 | ||
2257 | return nlmsg_end(skb, nlh); | 2437 | return nlmsg_end(skb, nlh); |
2258 | 2438 | ||
2439 | nla_put_failure: | ||
2259 | nlmsg_failure: | 2440 | nlmsg_failure: |
2260 | nlmsg_cancel(skb, nlh); | 2441 | nlmsg_cancel(skb, nlh); |
2261 | return -EMSGSIZE; | 2442 | return -EMSGSIZE; |
@@ -2342,6 +2523,7 @@ static inline size_t xfrm_polexpire_msgsize(struct xfrm_policy *xp) | |||
2342 | return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) | 2523 | return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) |
2343 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) | 2524 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) |
2344 | + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) | 2525 | + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) |
2526 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
2345 | + userpolicy_type_attrsize(); | 2527 | + userpolicy_type_attrsize(); |
2346 | } | 2528 | } |
2347 | 2529 | ||
@@ -2364,10 +2546,13 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
2364 | goto nlmsg_failure; | 2546 | goto nlmsg_failure; |
2365 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2547 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2366 | goto nlmsg_failure; | 2548 | goto nlmsg_failure; |
2549 | if (xfrm_mark_put(skb, &xp->mark)) | ||
2550 | goto nla_put_failure; | ||
2367 | upe->hard = !!hard; | 2551 | upe->hard = !!hard; |
2368 | 2552 | ||
2369 | return nlmsg_end(skb, nlh); | 2553 | return nlmsg_end(skb, nlh); |
2370 | 2554 | ||
2555 | nla_put_failure: | ||
2371 | nlmsg_failure: | 2556 | nlmsg_failure: |
2372 | nlmsg_cancel(skb, nlh); | 2557 | nlmsg_cancel(skb, nlh); |
2373 | return -EMSGSIZE; | 2558 | return -EMSGSIZE; |
@@ -2404,6 +2589,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
2404 | headlen = sizeof(*id); | 2589 | headlen = sizeof(*id); |
2405 | } | 2590 | } |
2406 | len += userpolicy_type_attrsize(); | 2591 | len += userpolicy_type_attrsize(); |
2592 | len += nla_total_size(sizeof(struct xfrm_mark)); | ||
2407 | len += NLMSG_ALIGN(headlen); | 2593 | len += NLMSG_ALIGN(headlen); |
2408 | 2594 | ||
2409 | skb = nlmsg_new(len, GFP_ATOMIC); | 2595 | skb = nlmsg_new(len, GFP_ATOMIC); |
@@ -2439,10 +2625,14 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
2439 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2625 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2440 | goto nlmsg_failure; | 2626 | goto nlmsg_failure; |
2441 | 2627 | ||
2628 | if (xfrm_mark_put(skb, &xp->mark)) | ||
2629 | goto nla_put_failure; | ||
2630 | |||
2442 | nlmsg_end(skb, nlh); | 2631 | nlmsg_end(skb, nlh); |
2443 | 2632 | ||
2444 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2633 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
2445 | 2634 | ||
2635 | nla_put_failure: | ||
2446 | nlmsg_failure: | 2636 | nlmsg_failure: |
2447 | kfree_skb(skb); | 2637 | kfree_skb(skb); |
2448 | return -1; | 2638 | return -1; |
@@ -2608,22 +2798,24 @@ static int __net_init xfrm_user_net_init(struct net *net) | |||
2608 | xfrm_netlink_rcv, NULL, THIS_MODULE); | 2798 | xfrm_netlink_rcv, NULL, THIS_MODULE); |
2609 | if (nlsk == NULL) | 2799 | if (nlsk == NULL) |
2610 | return -ENOMEM; | 2800 | return -ENOMEM; |
2801 | net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */ | ||
2611 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); | 2802 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); |
2612 | return 0; | 2803 | return 0; |
2613 | } | 2804 | } |
2614 | 2805 | ||
2615 | static void __net_exit xfrm_user_net_exit(struct net *net) | 2806 | static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list) |
2616 | { | 2807 | { |
2617 | struct sock *nlsk = net->xfrm.nlsk; | 2808 | struct net *net; |
2618 | 2809 | list_for_each_entry(net, net_exit_list, exit_list) | |
2619 | rcu_assign_pointer(net->xfrm.nlsk, NULL); | 2810 | rcu_assign_pointer(net->xfrm.nlsk, NULL); |
2620 | synchronize_rcu(); | 2811 | synchronize_net(); |
2621 | netlink_kernel_release(nlsk); | 2812 | list_for_each_entry(net, net_exit_list, exit_list) |
2813 | netlink_kernel_release(net->xfrm.nlsk_stash); | ||
2622 | } | 2814 | } |
2623 | 2815 | ||
2624 | static struct pernet_operations xfrm_user_net_ops = { | 2816 | static struct pernet_operations xfrm_user_net_ops = { |
2625 | .init = xfrm_user_net_init, | 2817 | .init = xfrm_user_net_init, |
2626 | .exit = xfrm_user_net_exit, | 2818 | .exit_batch = xfrm_user_net_exit, |
2627 | }; | 2819 | }; |
2628 | 2820 | ||
2629 | static int __init xfrm_user_init(void) | 2821 | static int __init xfrm_user_init(void) |