diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_algo.c | 6 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 154 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 14 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 149 |
4 files changed, 261 insertions, 62 deletions
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index 2f4531fcac..6ed3302312 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c | |||
@@ -540,8 +540,7 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, | |||
540 | start = end; | 540 | start = end; |
541 | } | 541 | } |
542 | } | 542 | } |
543 | if (len) | 543 | BUG_ON(len); |
544 | BUG(); | ||
545 | } | 544 | } |
546 | EXPORT_SYMBOL_GPL(skb_icv_walk); | 545 | EXPORT_SYMBOL_GPL(skb_icv_walk); |
547 | 546 | ||
@@ -610,8 +609,7 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) | |||
610 | start = end; | 609 | start = end; |
611 | } | 610 | } |
612 | } | 611 | } |
613 | if (len) | 612 | BUG_ON(len); |
614 | BUG(); | ||
615 | return elt; | 613 | return elt; |
616 | } | 614 | } |
617 | EXPORT_SYMBOL_GPL(skb_to_sgvec); | 615 | EXPORT_SYMBOL_GPL(skb_to_sgvec); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 0db9e57013..077bbf9fb9 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -10,7 +10,7 @@ | |||
10 | * YOSHIFUJI Hideaki | 10 | * YOSHIFUJI Hideaki |
11 | * Split up af-specific portion | 11 | * Split up af-specific portion |
12 | * Derek Atkins <derek@ihtfp.com> Add the post_input processor | 12 | * Derek Atkins <derek@ihtfp.com> Add the post_input processor |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <asm/bug.h> | 16 | #include <asm/bug.h> |
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
23 | #include <linux/notifier.h> | 23 | #include <linux/notifier.h> |
24 | #include <linux/netdevice.h> | 24 | #include <linux/netdevice.h> |
25 | #include <linux/netfilter.h> | ||
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
26 | #include <net/xfrm.h> | 27 | #include <net/xfrm.h> |
27 | #include <net/ip.h> | 28 | #include <net/ip.h> |
@@ -247,15 +248,14 @@ EXPORT_SYMBOL(xfrm_policy_alloc); | |||
247 | 248 | ||
248 | void __xfrm_policy_destroy(struct xfrm_policy *policy) | 249 | void __xfrm_policy_destroy(struct xfrm_policy *policy) |
249 | { | 250 | { |
250 | if (!policy->dead) | 251 | BUG_ON(!policy->dead); |
251 | BUG(); | ||
252 | 252 | ||
253 | if (policy->bundles) | 253 | BUG_ON(policy->bundles); |
254 | BUG(); | ||
255 | 254 | ||
256 | if (del_timer(&policy->timer)) | 255 | if (del_timer(&policy->timer)) |
257 | BUG(); | 256 | BUG(); |
258 | 257 | ||
258 | security_xfrm_policy_free(policy); | ||
259 | kfree(policy); | 259 | kfree(policy); |
260 | } | 260 | } |
261 | EXPORT_SYMBOL(__xfrm_policy_destroy); | 261 | EXPORT_SYMBOL(__xfrm_policy_destroy); |
@@ -346,10 +346,12 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
346 | struct xfrm_policy *pol, **p; | 346 | struct xfrm_policy *pol, **p; |
347 | struct xfrm_policy *delpol = NULL; | 347 | struct xfrm_policy *delpol = NULL; |
348 | struct xfrm_policy **newpos = NULL; | 348 | struct xfrm_policy **newpos = NULL; |
349 | struct dst_entry *gc_list; | ||
349 | 350 | ||
350 | write_lock_bh(&xfrm_policy_lock); | 351 | write_lock_bh(&xfrm_policy_lock); |
351 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 352 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { |
352 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) { | 353 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && |
354 | xfrm_sec_ctx_match(pol->security, policy->security)) { | ||
353 | if (excl) { | 355 | if (excl) { |
354 | write_unlock_bh(&xfrm_policy_lock); | 356 | write_unlock_bh(&xfrm_policy_lock); |
355 | return -EEXIST; | 357 | return -EEXIST; |
@@ -381,21 +383,49 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
381 | xfrm_pol_hold(policy); | 383 | xfrm_pol_hold(policy); |
382 | write_unlock_bh(&xfrm_policy_lock); | 384 | write_unlock_bh(&xfrm_policy_lock); |
383 | 385 | ||
384 | if (delpol) { | 386 | if (delpol) |
385 | xfrm_policy_kill(delpol); | 387 | xfrm_policy_kill(delpol); |
388 | |||
389 | read_lock_bh(&xfrm_policy_lock); | ||
390 | gc_list = NULL; | ||
391 | for (policy = policy->next; policy; policy = policy->next) { | ||
392 | struct dst_entry *dst; | ||
393 | |||
394 | write_lock(&policy->lock); | ||
395 | dst = policy->bundles; | ||
396 | if (dst) { | ||
397 | struct dst_entry *tail = dst; | ||
398 | while (tail->next) | ||
399 | tail = tail->next; | ||
400 | tail->next = gc_list; | ||
401 | gc_list = dst; | ||
402 | |||
403 | policy->bundles = NULL; | ||
404 | } | ||
405 | write_unlock(&policy->lock); | ||
406 | } | ||
407 | read_unlock_bh(&xfrm_policy_lock); | ||
408 | |||
409 | while (gc_list) { | ||
410 | struct dst_entry *dst = gc_list; | ||
411 | |||
412 | gc_list = dst->next; | ||
413 | dst_free(dst); | ||
386 | } | 414 | } |
415 | |||
387 | return 0; | 416 | return 0; |
388 | } | 417 | } |
389 | EXPORT_SYMBOL(xfrm_policy_insert); | 418 | EXPORT_SYMBOL(xfrm_policy_insert); |
390 | 419 | ||
391 | struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, | 420 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, |
392 | int delete) | 421 | struct xfrm_sec_ctx *ctx, int delete) |
393 | { | 422 | { |
394 | struct xfrm_policy *pol, **p; | 423 | struct xfrm_policy *pol, **p; |
395 | 424 | ||
396 | write_lock_bh(&xfrm_policy_lock); | 425 | write_lock_bh(&xfrm_policy_lock); |
397 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 426 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { |
398 | if (memcmp(sel, &pol->selector, sizeof(*sel)) == 0) { | 427 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && |
428 | (xfrm_sec_ctx_match(ctx, pol->security))) { | ||
399 | xfrm_pol_hold(pol); | 429 | xfrm_pol_hold(pol); |
400 | if (delete) | 430 | if (delete) |
401 | *p = pol->next; | 431 | *p = pol->next; |
@@ -410,7 +440,7 @@ struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, | |||
410 | } | 440 | } |
411 | return pol; | 441 | return pol; |
412 | } | 442 | } |
413 | EXPORT_SYMBOL(xfrm_policy_bysel); | 443 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
414 | 444 | ||
415 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 445 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) |
416 | { | 446 | { |
@@ -491,7 +521,7 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
491 | 521 | ||
492 | /* Find policy to apply to this flow. */ | 522 | /* Find policy to apply to this flow. */ |
493 | 523 | ||
494 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | 524 | static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, |
495 | void **objp, atomic_t **obj_refp) | 525 | void **objp, atomic_t **obj_refp) |
496 | { | 526 | { |
497 | struct xfrm_policy *pol; | 527 | struct xfrm_policy *pol; |
@@ -505,9 +535,12 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
505 | continue; | 535 | continue; |
506 | 536 | ||
507 | match = xfrm_selector_match(sel, fl, family); | 537 | match = xfrm_selector_match(sel, fl, family); |
538 | |||
508 | if (match) { | 539 | if (match) { |
509 | xfrm_pol_hold(pol); | 540 | if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) { |
510 | break; | 541 | xfrm_pol_hold(pol); |
542 | break; | ||
543 | } | ||
511 | } | 544 | } |
512 | } | 545 | } |
513 | read_unlock_bh(&xfrm_policy_lock); | 546 | read_unlock_bh(&xfrm_policy_lock); |
@@ -515,15 +548,37 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
515 | *obj_refp = &pol->refcnt; | 548 | *obj_refp = &pol->refcnt; |
516 | } | 549 | } |
517 | 550 | ||
518 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl) | 551 | static inline int policy_to_flow_dir(int dir) |
552 | { | ||
553 | if (XFRM_POLICY_IN == FLOW_DIR_IN && | ||
554 | XFRM_POLICY_OUT == FLOW_DIR_OUT && | ||
555 | XFRM_POLICY_FWD == FLOW_DIR_FWD) | ||
556 | return dir; | ||
557 | switch (dir) { | ||
558 | default: | ||
559 | case XFRM_POLICY_IN: | ||
560 | return FLOW_DIR_IN; | ||
561 | case XFRM_POLICY_OUT: | ||
562 | return FLOW_DIR_OUT; | ||
563 | case XFRM_POLICY_FWD: | ||
564 | return FLOW_DIR_FWD; | ||
565 | }; | ||
566 | } | ||
567 | |||
568 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) | ||
519 | { | 569 | { |
520 | struct xfrm_policy *pol; | 570 | struct xfrm_policy *pol; |
521 | 571 | ||
522 | read_lock_bh(&xfrm_policy_lock); | 572 | read_lock_bh(&xfrm_policy_lock); |
523 | if ((pol = sk->sk_policy[dir]) != NULL) { | 573 | if ((pol = sk->sk_policy[dir]) != NULL) { |
524 | int match = xfrm_selector_match(&pol->selector, fl, | 574 | int match = xfrm_selector_match(&pol->selector, fl, |
525 | sk->sk_family); | 575 | sk->sk_family); |
576 | int err = 0; | ||
577 | |||
526 | if (match) | 578 | if (match) |
579 | err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir)); | ||
580 | |||
581 | if (match && !err) | ||
527 | xfrm_pol_hold(pol); | 582 | xfrm_pol_hold(pol); |
528 | else | 583 | else |
529 | pol = NULL; | 584 | pol = NULL; |
@@ -596,6 +651,10 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
596 | 651 | ||
597 | if (newp) { | 652 | if (newp) { |
598 | newp->selector = old->selector; | 653 | newp->selector = old->selector; |
654 | if (security_xfrm_policy_clone(old, newp)) { | ||
655 | kfree(newp); | ||
656 | return NULL; /* ENOMEM */ | ||
657 | } | ||
599 | newp->lft = old->lft; | 658 | newp->lft = old->lft; |
600 | newp->curlft = old->curlft; | 659 | newp->curlft = old->curlft; |
601 | newp->action = old->action; | 660 | newp->action = old->action; |
@@ -707,22 +766,6 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, | |||
707 | return err; | 766 | return err; |
708 | } | 767 | } |
709 | 768 | ||
710 | static inline int policy_to_flow_dir(int dir) | ||
711 | { | ||
712 | if (XFRM_POLICY_IN == FLOW_DIR_IN && | ||
713 | XFRM_POLICY_OUT == FLOW_DIR_OUT && | ||
714 | XFRM_POLICY_FWD == FLOW_DIR_FWD) | ||
715 | return dir; | ||
716 | switch (dir) { | ||
717 | default: | ||
718 | case XFRM_POLICY_IN: | ||
719 | return FLOW_DIR_IN; | ||
720 | case XFRM_POLICY_OUT: | ||
721 | return FLOW_DIR_OUT; | ||
722 | case XFRM_POLICY_FWD: | ||
723 | return FLOW_DIR_FWD; | ||
724 | }; | ||
725 | } | ||
726 | 769 | ||
727 | static int stale_bundle(struct dst_entry *dst); | 770 | static int stale_bundle(struct dst_entry *dst); |
728 | 771 | ||
@@ -741,19 +784,20 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
741 | int err; | 784 | int err; |
742 | u32 genid; | 785 | u32 genid; |
743 | u16 family = dst_orig->ops->family; | 786 | u16 family = dst_orig->ops->family; |
787 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | ||
788 | u32 sk_sid = security_sk_sid(sk, fl, dir); | ||
744 | restart: | 789 | restart: |
745 | genid = atomic_read(&flow_cache_genid); | 790 | genid = atomic_read(&flow_cache_genid); |
746 | policy = NULL; | 791 | policy = NULL; |
747 | if (sk && sk->sk_policy[1]) | 792 | if (sk && sk->sk_policy[1]) |
748 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | 793 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid); |
749 | 794 | ||
750 | if (!policy) { | 795 | if (!policy) { |
751 | /* To accelerate a bit... */ | 796 | /* To accelerate a bit... */ |
752 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 797 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) |
753 | return 0; | 798 | return 0; |
754 | 799 | ||
755 | policy = flow_cache_lookup(fl, family, | 800 | policy = flow_cache_lookup(fl, sk_sid, family, dir, |
756 | policy_to_flow_dir(XFRM_POLICY_OUT), | ||
757 | xfrm_policy_lookup); | 801 | xfrm_policy_lookup); |
758 | } | 802 | } |
759 | 803 | ||
@@ -906,8 +950,8 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | |||
906 | return start; | 950 | return start; |
907 | } | 951 | } |
908 | 952 | ||
909 | static int | 953 | int |
910 | _decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) | 954 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) |
911 | { | 955 | { |
912 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 956 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
913 | 957 | ||
@@ -918,6 +962,7 @@ _decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) | |||
918 | xfrm_policy_put_afinfo(afinfo); | 962 | xfrm_policy_put_afinfo(afinfo); |
919 | return 0; | 963 | return 0; |
920 | } | 964 | } |
965 | EXPORT_SYMBOL(xfrm_decode_session); | ||
921 | 966 | ||
922 | static inline int secpath_has_tunnel(struct sec_path *sp, int k) | 967 | static inline int secpath_has_tunnel(struct sec_path *sp, int k) |
923 | { | 968 | { |
@@ -934,16 +979,21 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
934 | { | 979 | { |
935 | struct xfrm_policy *pol; | 980 | struct xfrm_policy *pol; |
936 | struct flowi fl; | 981 | struct flowi fl; |
982 | u8 fl_dir = policy_to_flow_dir(dir); | ||
983 | u32 sk_sid; | ||
937 | 984 | ||
938 | if (_decode_session(skb, &fl, family) < 0) | 985 | if (xfrm_decode_session(skb, &fl, family) < 0) |
939 | return 0; | 986 | return 0; |
987 | nf_nat_decode_session(skb, &fl, family); | ||
988 | |||
989 | sk_sid = security_sk_sid(sk, &fl, fl_dir); | ||
940 | 990 | ||
941 | /* First, check used SA against their selectors. */ | 991 | /* First, check used SA against their selectors. */ |
942 | if (skb->sp) { | 992 | if (skb->sp) { |
943 | int i; | 993 | int i; |
944 | 994 | ||
945 | for (i=skb->sp->len-1; i>=0; i--) { | 995 | for (i=skb->sp->len-1; i>=0; i--) { |
946 | struct sec_decap_state *xvec = &(skb->sp->x[i]); | 996 | struct sec_decap_state *xvec = &(skb->sp->x[i]); |
947 | if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) | 997 | if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) |
948 | return 0; | 998 | return 0; |
949 | 999 | ||
@@ -958,11 +1008,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
958 | 1008 | ||
959 | pol = NULL; | 1009 | pol = NULL; |
960 | if (sk && sk->sk_policy[dir]) | 1010 | if (sk && sk->sk_policy[dir]) |
961 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); | 1011 | pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid); |
962 | 1012 | ||
963 | if (!pol) | 1013 | if (!pol) |
964 | pol = flow_cache_lookup(&fl, family, | 1014 | pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir, |
965 | policy_to_flow_dir(dir), | ||
966 | xfrm_policy_lookup); | 1015 | xfrm_policy_lookup); |
967 | 1016 | ||
968 | if (!pol) | 1017 | if (!pol) |
@@ -1007,20 +1056,19 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) | |||
1007 | { | 1056 | { |
1008 | struct flowi fl; | 1057 | struct flowi fl; |
1009 | 1058 | ||
1010 | if (_decode_session(skb, &fl, family) < 0) | 1059 | if (xfrm_decode_session(skb, &fl, family) < 0) |
1011 | return 0; | 1060 | return 0; |
1012 | 1061 | ||
1013 | return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; | 1062 | return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; |
1014 | } | 1063 | } |
1015 | EXPORT_SYMBOL(__xfrm_route_forward); | 1064 | EXPORT_SYMBOL(__xfrm_route_forward); |
1016 | 1065 | ||
1017 | /* Optimize later using cookies and generation ids. */ | ||
1018 | |||
1019 | static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) | 1066 | static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) |
1020 | { | 1067 | { |
1021 | if (!stale_bundle(dst)) | 1068 | /* If it is marked obsolete, which is how we even get here, |
1022 | return dst; | 1069 | * then we have purged it from the policy bundle list and we |
1023 | 1070 | * did that for a good reason. | |
1071 | */ | ||
1024 | return NULL; | 1072 | return NULL; |
1025 | } | 1073 | } |
1026 | 1074 | ||
@@ -1104,6 +1152,16 @@ int xfrm_flush_bundles(void) | |||
1104 | return 0; | 1152 | return 0; |
1105 | } | 1153 | } |
1106 | 1154 | ||
1155 | static int always_true(struct dst_entry *dst) | ||
1156 | { | ||
1157 | return 1; | ||
1158 | } | ||
1159 | |||
1160 | void xfrm_flush_all_bundles(void) | ||
1161 | { | ||
1162 | xfrm_prune_bundles(always_true); | ||
1163 | } | ||
1164 | |||
1107 | void xfrm_init_pmtu(struct dst_entry *dst) | 1165 | void xfrm_init_pmtu(struct dst_entry *dst) |
1108 | { | 1166 | { |
1109 | do { | 1167 | do { |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 7cf48aa6c9..e12d0be5f9 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -10,7 +10,7 @@ | |||
10 | * Split up af-specific functions | 10 | * Split up af-specific functions |
11 | * Derek Atkins <derek@ihtfp.com> | 11 | * Derek Atkins <derek@ihtfp.com> |
12 | * Add UDP Encapsulation | 12 | * Add UDP Encapsulation |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/workqueue.h> | 16 | #include <linux/workqueue.h> |
@@ -70,6 +70,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
70 | x->type->destructor(x); | 70 | x->type->destructor(x); |
71 | xfrm_put_type(x->type); | 71 | xfrm_put_type(x->type); |
72 | } | 72 | } |
73 | security_xfrm_state_free(x); | ||
73 | kfree(x); | 74 | kfree(x); |
74 | } | 75 | } |
75 | 76 | ||
@@ -343,7 +344,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
343 | selector. | 344 | selector. |
344 | */ | 345 | */ |
345 | if (x->km.state == XFRM_STATE_VALID) { | 346 | if (x->km.state == XFRM_STATE_VALID) { |
346 | if (!xfrm_selector_match(&x->sel, fl, family)) | 347 | if (!xfrm_selector_match(&x->sel, fl, family) || |
348 | !xfrm_sec_ctx_match(pol->security, x->security)) | ||
347 | continue; | 349 | continue; |
348 | if (!best || | 350 | if (!best || |
349 | best->km.dying > x->km.dying || | 351 | best->km.dying > x->km.dying || |
@@ -354,7 +356,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
354 | acquire_in_progress = 1; | 356 | acquire_in_progress = 1; |
355 | } else if (x->km.state == XFRM_STATE_ERROR || | 357 | } else if (x->km.state == XFRM_STATE_ERROR || |
356 | x->km.state == XFRM_STATE_EXPIRED) { | 358 | x->km.state == XFRM_STATE_EXPIRED) { |
357 | if (xfrm_selector_match(&x->sel, fl, family)) | 359 | if (xfrm_selector_match(&x->sel, fl, family) && |
360 | xfrm_sec_ctx_match(pol->security, x->security)) | ||
358 | error = -ESRCH; | 361 | error = -ESRCH; |
359 | } | 362 | } |
360 | } | 363 | } |
@@ -431,6 +434,8 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
431 | spin_lock_bh(&xfrm_state_lock); | 434 | spin_lock_bh(&xfrm_state_lock); |
432 | __xfrm_state_insert(x); | 435 | __xfrm_state_insert(x); |
433 | spin_unlock_bh(&xfrm_state_lock); | 436 | spin_unlock_bh(&xfrm_state_lock); |
437 | |||
438 | xfrm_flush_all_bundles(); | ||
434 | } | 439 | } |
435 | EXPORT_SYMBOL(xfrm_state_insert); | 440 | EXPORT_SYMBOL(xfrm_state_insert); |
436 | 441 | ||
@@ -478,6 +483,9 @@ out: | |||
478 | spin_unlock_bh(&xfrm_state_lock); | 483 | spin_unlock_bh(&xfrm_state_lock); |
479 | xfrm_state_put_afinfo(afinfo); | 484 | xfrm_state_put_afinfo(afinfo); |
480 | 485 | ||
486 | if (!err) | ||
487 | xfrm_flush_all_bundles(); | ||
488 | |||
481 | if (x1) { | 489 | if (x1) { |
482 | xfrm_state_delete(x1); | 490 | xfrm_state_delete(x1); |
483 | xfrm_state_put(x1); | 491 | xfrm_state_put(x1); |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0cdd9a07e0..ac87a09ba8 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Kazunori MIYAZAWA @USAGI | 7 | * Kazunori MIYAZAWA @USAGI |
8 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 8 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
9 | * IPv6 support | 9 | * IPv6 support |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
@@ -88,6 +88,34 @@ static int verify_encap_tmpl(struct rtattr **xfrma) | |||
88 | return 0; | 88 | return 0; |
89 | } | 89 | } |
90 | 90 | ||
91 | |||
92 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | ||
93 | { | ||
94 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1]; | ||
95 | struct xfrm_user_sec_ctx *uctx; | ||
96 | int len = 0; | ||
97 | |||
98 | if (!rt) | ||
99 | return 0; | ||
100 | |||
101 | if (rt->rta_len < sizeof(*uctx)) | ||
102 | return -EINVAL; | ||
103 | |||
104 | uctx = RTA_DATA(rt); | ||
105 | |||
106 | if (uctx->ctx_len > PAGE_SIZE) | ||
107 | return -EINVAL; | ||
108 | |||
109 | len += sizeof(struct xfrm_user_sec_ctx); | ||
110 | len += uctx->ctx_len; | ||
111 | |||
112 | if (uctx->len != len) | ||
113 | return -EINVAL; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | |||
91 | static int verify_newsa_info(struct xfrm_usersa_info *p, | 119 | static int verify_newsa_info(struct xfrm_usersa_info *p, |
92 | struct rtattr **xfrma) | 120 | struct rtattr **xfrma) |
93 | { | 121 | { |
@@ -145,6 +173,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
145 | goto out; | 173 | goto out; |
146 | if ((err = verify_encap_tmpl(xfrma))) | 174 | if ((err = verify_encap_tmpl(xfrma))) |
147 | goto out; | 175 | goto out; |
176 | if ((err = verify_sec_ctx_len(xfrma))) | ||
177 | goto out; | ||
148 | 178 | ||
149 | err = -EINVAL; | 179 | err = -EINVAL; |
150 | switch (p->mode) { | 180 | switch (p->mode) { |
@@ -209,6 +239,30 @@ static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_a | |||
209 | return 0; | 239 | return 0; |
210 | } | 240 | } |
211 | 241 | ||
242 | |||
243 | static inline int xfrm_user_sec_ctx_size(struct xfrm_policy *xp) | ||
244 | { | ||
245 | struct xfrm_sec_ctx *xfrm_ctx = xp->security; | ||
246 | int len = 0; | ||
247 | |||
248 | if (xfrm_ctx) { | ||
249 | len += sizeof(struct xfrm_user_sec_ctx); | ||
250 | len += xfrm_ctx->ctx_len; | ||
251 | } | ||
252 | return len; | ||
253 | } | ||
254 | |||
255 | static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) | ||
256 | { | ||
257 | struct xfrm_user_sec_ctx *uctx; | ||
258 | |||
259 | if (!u_arg) | ||
260 | return 0; | ||
261 | |||
262 | uctx = RTA_DATA(u_arg); | ||
263 | return security_xfrm_state_alloc(x, uctx); | ||
264 | } | ||
265 | |||
212 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 266 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
213 | { | 267 | { |
214 | memcpy(&x->id, &p->id, sizeof(x->id)); | 268 | memcpy(&x->id, &p->id, sizeof(x->id)); |
@@ -253,6 +307,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
253 | if (err) | 307 | if (err) |
254 | goto error; | 308 | goto error; |
255 | 309 | ||
310 | if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1]))) | ||
311 | goto error; | ||
312 | |||
256 | x->km.seq = p->seq; | 313 | x->km.seq = p->seq; |
257 | 314 | ||
258 | return x; | 315 | return x; |
@@ -272,11 +329,11 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
272 | int err; | 329 | int err; |
273 | struct km_event c; | 330 | struct km_event c; |
274 | 331 | ||
275 | err = verify_newsa_info(p, (struct rtattr **) xfrma); | 332 | err = verify_newsa_info(p, (struct rtattr **)xfrma); |
276 | if (err) | 333 | if (err) |
277 | return err; | 334 | return err; |
278 | 335 | ||
279 | x = xfrm_state_construct(p, (struct rtattr **) xfrma, &err); | 336 | x = xfrm_state_construct(p, (struct rtattr **)xfrma, &err); |
280 | if (!x) | 337 | if (!x) |
281 | return err; | 338 | return err; |
282 | 339 | ||
@@ -390,6 +447,19 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
390 | if (x->encap) | 447 | if (x->encap) |
391 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 448 | RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
392 | 449 | ||
450 | if (x->security) { | ||
451 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | ||
452 | x->security->ctx_len; | ||
453 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | ||
454 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
455 | |||
456 | uctx->exttype = XFRMA_SEC_CTX; | ||
457 | uctx->len = ctx_size; | ||
458 | uctx->ctx_doi = x->security->ctx_doi; | ||
459 | uctx->ctx_alg = x->security->ctx_alg; | ||
460 | uctx->ctx_len = x->security->ctx_len; | ||
461 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); | ||
462 | } | ||
393 | nlh->nlmsg_len = skb->tail - b; | 463 | nlh->nlmsg_len = skb->tail - b; |
394 | out: | 464 | out: |
395 | sp->this_idx++; | 465 | sp->this_idx++; |
@@ -603,6 +673,18 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | |||
603 | return verify_policy_dir(p->dir); | 673 | return verify_policy_dir(p->dir); |
604 | } | 674 | } |
605 | 675 | ||
676 | static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma) | ||
677 | { | ||
678 | struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1]; | ||
679 | struct xfrm_user_sec_ctx *uctx; | ||
680 | |||
681 | if (!rt) | ||
682 | return 0; | ||
683 | |||
684 | uctx = RTA_DATA(rt); | ||
685 | return security_xfrm_policy_alloc(pol, uctx); | ||
686 | } | ||
687 | |||
606 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | 688 | static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, |
607 | int nr) | 689 | int nr) |
608 | { | 690 | { |
@@ -681,7 +763,10 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
681 | } | 763 | } |
682 | 764 | ||
683 | copy_from_user_policy(xp, p); | 765 | copy_from_user_policy(xp, p); |
684 | err = copy_from_user_tmpl(xp, xfrma); | 766 | |
767 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | ||
768 | err = copy_from_user_sec_ctx(xp, xfrma); | ||
769 | |||
685 | if (err) { | 770 | if (err) { |
686 | *errp = err; | 771 | *errp = err; |
687 | kfree(xp); | 772 | kfree(xp); |
@@ -702,8 +787,11 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
702 | err = verify_newpolicy_info(p); | 787 | err = verify_newpolicy_info(p); |
703 | if (err) | 788 | if (err) |
704 | return err; | 789 | return err; |
790 | err = verify_sec_ctx_len((struct rtattr **)xfrma); | ||
791 | if (err) | ||
792 | return err; | ||
705 | 793 | ||
706 | xp = xfrm_policy_construct(p, (struct rtattr **) xfrma, &err); | 794 | xp = xfrm_policy_construct(p, (struct rtattr **)xfrma, &err); |
707 | if (!xp) | 795 | if (!xp) |
708 | return err; | 796 | return err; |
709 | 797 | ||
@@ -714,6 +802,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
714 | excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; | 802 | excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; |
715 | err = xfrm_policy_insert(p->dir, xp, excl); | 803 | err = xfrm_policy_insert(p->dir, xp, excl); |
716 | if (err) { | 804 | if (err) { |
805 | security_xfrm_policy_free(xp); | ||
717 | kfree(xp); | 806 | kfree(xp); |
718 | return err; | 807 | return err; |
719 | } | 808 | } |
@@ -761,6 +850,27 @@ rtattr_failure: | |||
761 | return -1; | 850 | return -1; |
762 | } | 851 | } |
763 | 852 | ||
853 | static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) | ||
854 | { | ||
855 | if (xp->security) { | ||
856 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | ||
857 | xp->security->ctx_len; | ||
858 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | ||
859 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
860 | |||
861 | uctx->exttype = XFRMA_SEC_CTX; | ||
862 | uctx->len = ctx_size; | ||
863 | uctx->ctx_doi = xp->security->ctx_doi; | ||
864 | uctx->ctx_alg = xp->security->ctx_alg; | ||
865 | uctx->ctx_len = xp->security->ctx_len; | ||
866 | memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len); | ||
867 | } | ||
868 | return 0; | ||
869 | |||
870 | rtattr_failure: | ||
871 | return -1; | ||
872 | } | ||
873 | |||
764 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) | 874 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) |
765 | { | 875 | { |
766 | struct xfrm_dump_info *sp = ptr; | 876 | struct xfrm_dump_info *sp = ptr; |
@@ -782,6 +892,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
782 | copy_to_user_policy(xp, p, dir); | 892 | copy_to_user_policy(xp, p, dir); |
783 | if (copy_to_user_tmpl(xp, skb) < 0) | 893 | if (copy_to_user_tmpl(xp, skb) < 0) |
784 | goto nlmsg_failure; | 894 | goto nlmsg_failure; |
895 | if (copy_to_user_sec_ctx(xp, skb)) | ||
896 | goto nlmsg_failure; | ||
785 | 897 | ||
786 | nlh->nlmsg_len = skb->tail - b; | 898 | nlh->nlmsg_len = skb->tail - b; |
787 | out: | 899 | out: |
@@ -852,8 +964,25 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
852 | 964 | ||
853 | if (p->index) | 965 | if (p->index) |
854 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 966 | xp = xfrm_policy_byid(p->dir, p->index, delete); |
855 | else | 967 | else { |
856 | xp = xfrm_policy_bysel(p->dir, &p->sel, delete); | 968 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
969 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | ||
970 | struct xfrm_policy tmp; | ||
971 | |||
972 | err = verify_sec_ctx_len(rtattrs); | ||
973 | if (err) | ||
974 | return err; | ||
975 | |||
976 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
977 | if (rt) { | ||
978 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
979 | |||
980 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | ||
981 | return err; | ||
982 | } | ||
983 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete); | ||
984 | security_xfrm_policy_free(&tmp); | ||
985 | } | ||
857 | if (xp == NULL) | 986 | if (xp == NULL) |
858 | return -ENOENT; | 987 | return -ENOENT; |
859 | 988 | ||
@@ -1224,6 +1353,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
1224 | 1353 | ||
1225 | if (copy_to_user_tmpl(xp, skb) < 0) | 1354 | if (copy_to_user_tmpl(xp, skb) < 0) |
1226 | goto nlmsg_failure; | 1355 | goto nlmsg_failure; |
1356 | if (copy_to_user_sec_ctx(xp, skb)) | ||
1357 | goto nlmsg_failure; | ||
1227 | 1358 | ||
1228 | nlh->nlmsg_len = skb->tail - b; | 1359 | nlh->nlmsg_len = skb->tail - b; |
1229 | return skb->len; | 1360 | return skb->len; |
@@ -1241,6 +1372,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
1241 | 1372 | ||
1242 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 1373 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
1243 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); | 1374 | len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire)); |
1375 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | ||
1244 | skb = alloc_skb(len, GFP_ATOMIC); | 1376 | skb = alloc_skb(len, GFP_ATOMIC); |
1245 | if (skb == NULL) | 1377 | if (skb == NULL) |
1246 | return -ENOMEM; | 1378 | return -ENOMEM; |
@@ -1324,6 +1456,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
1324 | copy_to_user_policy(xp, &upe->pol, dir); | 1456 | copy_to_user_policy(xp, &upe->pol, dir); |
1325 | if (copy_to_user_tmpl(xp, skb) < 0) | 1457 | if (copy_to_user_tmpl(xp, skb) < 0) |
1326 | goto nlmsg_failure; | 1458 | goto nlmsg_failure; |
1459 | if (copy_to_user_sec_ctx(xp, skb)) | ||
1460 | goto nlmsg_failure; | ||
1327 | upe->hard = !!hard; | 1461 | upe->hard = !!hard; |
1328 | 1462 | ||
1329 | nlh->nlmsg_len = skb->tail - b; | 1463 | nlh->nlmsg_len = skb->tail - b; |
@@ -1341,6 +1475,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve | |||
1341 | 1475 | ||
1342 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); | 1476 | len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); |
1343 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); | 1477 | len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire)); |
1478 | len += RTA_SPACE(xfrm_user_sec_ctx_size(xp)); | ||
1344 | skb = alloc_skb(len, GFP_ATOMIC); | 1479 | skb = alloc_skb(len, GFP_ATOMIC); |
1345 | if (skb == NULL) | 1480 | if (skb == NULL) |
1346 | return -ENOMEM; | 1481 | return -ENOMEM; |