diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 88 |
1 files changed, 54 insertions, 34 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d19e274b9c4a..64a447375fdb 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> |
| @@ -256,6 +256,7 @@ void __xfrm_policy_destroy(struct xfrm_policy *policy) | |||
| 256 | if (del_timer(&policy->timer)) | 256 | if (del_timer(&policy->timer)) |
| 257 | BUG(); | 257 | BUG(); |
| 258 | 258 | ||
| 259 | security_xfrm_policy_free(policy); | ||
| 259 | kfree(policy); | 260 | kfree(policy); |
| 260 | } | 261 | } |
| 261 | EXPORT_SYMBOL(__xfrm_policy_destroy); | 262 | EXPORT_SYMBOL(__xfrm_policy_destroy); |
| @@ -350,7 +351,8 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 350 | 351 | ||
| 351 | write_lock_bh(&xfrm_policy_lock); | 352 | write_lock_bh(&xfrm_policy_lock); |
| 352 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 353 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { |
| 353 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) { | 354 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && |
| 355 | xfrm_sec_ctx_match(pol->security, policy->security)) { | ||
| 354 | if (excl) { | 356 | if (excl) { |
| 355 | write_unlock_bh(&xfrm_policy_lock); | 357 | write_unlock_bh(&xfrm_policy_lock); |
| 356 | return -EEXIST; | 358 | return -EEXIST; |
| @@ -416,14 +418,15 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
| 416 | } | 418 | } |
| 417 | EXPORT_SYMBOL(xfrm_policy_insert); | 419 | EXPORT_SYMBOL(xfrm_policy_insert); |
| 418 | 420 | ||
| 419 | struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, | 421 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, |
| 420 | int delete) | 422 | struct xfrm_sec_ctx *ctx, int delete) |
| 421 | { | 423 | { |
| 422 | struct xfrm_policy *pol, **p; | 424 | struct xfrm_policy *pol, **p; |
| 423 | 425 | ||
| 424 | write_lock_bh(&xfrm_policy_lock); | 426 | write_lock_bh(&xfrm_policy_lock); |
| 425 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 427 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { |
| 426 | if (memcmp(sel, &pol->selector, sizeof(*sel)) == 0) { | 428 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && |
| 429 | (xfrm_sec_ctx_match(ctx, pol->security))) { | ||
| 427 | xfrm_pol_hold(pol); | 430 | xfrm_pol_hold(pol); |
| 428 | if (delete) | 431 | if (delete) |
| 429 | *p = pol->next; | 432 | *p = pol->next; |
| @@ -438,7 +441,7 @@ struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, | |||
| 438 | } | 441 | } |
| 439 | return pol; | 442 | return pol; |
| 440 | } | 443 | } |
| 441 | EXPORT_SYMBOL(xfrm_policy_bysel); | 444 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
| 442 | 445 | ||
| 443 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 446 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) |
| 444 | { | 447 | { |
| @@ -519,7 +522,7 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
| 519 | 522 | ||
| 520 | /* Find policy to apply to this flow. */ | 523 | /* Find policy to apply to this flow. */ |
| 521 | 524 | ||
| 522 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | 525 | static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, |
| 523 | void **objp, atomic_t **obj_refp) | 526 | void **objp, atomic_t **obj_refp) |
| 524 | { | 527 | { |
| 525 | struct xfrm_policy *pol; | 528 | struct xfrm_policy *pol; |
| @@ -533,9 +536,12 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
| 533 | continue; | 536 | continue; |
| 534 | 537 | ||
| 535 | match = xfrm_selector_match(sel, fl, family); | 538 | match = xfrm_selector_match(sel, fl, family); |
| 539 | |||
| 536 | if (match) { | 540 | if (match) { |
| 537 | xfrm_pol_hold(pol); | 541 | if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) { |
| 538 | break; | 542 | xfrm_pol_hold(pol); |
| 543 | break; | ||
| 544 | } | ||
| 539 | } | 545 | } |
| 540 | } | 546 | } |
| 541 | read_unlock_bh(&xfrm_policy_lock); | 547 | read_unlock_bh(&xfrm_policy_lock); |
| @@ -543,15 +549,37 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | |||
| 543 | *obj_refp = &pol->refcnt; | 549 | *obj_refp = &pol->refcnt; |
| 544 | } | 550 | } |
| 545 | 551 | ||
| 546 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl) | 552 | static inline int policy_to_flow_dir(int dir) |
| 553 | { | ||
| 554 | if (XFRM_POLICY_IN == FLOW_DIR_IN && | ||
| 555 | XFRM_POLICY_OUT == FLOW_DIR_OUT && | ||
| 556 | XFRM_POLICY_FWD == FLOW_DIR_FWD) | ||
| 557 | return dir; | ||
| 558 | switch (dir) { | ||
| 559 | default: | ||
| 560 | case XFRM_POLICY_IN: | ||
| 561 | return FLOW_DIR_IN; | ||
| 562 | case XFRM_POLICY_OUT: | ||
| 563 | return FLOW_DIR_OUT; | ||
| 564 | case XFRM_POLICY_FWD: | ||
| 565 | return FLOW_DIR_FWD; | ||
| 566 | }; | ||
| 567 | } | ||
| 568 | |||
| 569 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) | ||
| 547 | { | 570 | { |
| 548 | struct xfrm_policy *pol; | 571 | struct xfrm_policy *pol; |
| 549 | 572 | ||
| 550 | read_lock_bh(&xfrm_policy_lock); | 573 | read_lock_bh(&xfrm_policy_lock); |
| 551 | if ((pol = sk->sk_policy[dir]) != NULL) { | 574 | if ((pol = sk->sk_policy[dir]) != NULL) { |
| 552 | int match = xfrm_selector_match(&pol->selector, fl, | 575 | int match = xfrm_selector_match(&pol->selector, fl, |
| 553 | sk->sk_family); | 576 | sk->sk_family); |
| 577 | int err = 0; | ||
| 578 | |||
| 554 | if (match) | 579 | if (match) |
| 580 | err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir)); | ||
| 581 | |||
| 582 | if (match && !err) | ||
| 555 | xfrm_pol_hold(pol); | 583 | xfrm_pol_hold(pol); |
| 556 | else | 584 | else |
| 557 | pol = NULL; | 585 | pol = NULL; |
| @@ -624,6 +652,10 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
| 624 | 652 | ||
| 625 | if (newp) { | 653 | if (newp) { |
| 626 | newp->selector = old->selector; | 654 | newp->selector = old->selector; |
| 655 | if (security_xfrm_policy_clone(old, newp)) { | ||
| 656 | kfree(newp); | ||
| 657 | return NULL; /* ENOMEM */ | ||
| 658 | } | ||
| 627 | newp->lft = old->lft; | 659 | newp->lft = old->lft; |
| 628 | newp->curlft = old->curlft; | 660 | newp->curlft = old->curlft; |
| 629 | newp->action = old->action; | 661 | newp->action = old->action; |
| @@ -735,22 +767,6 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, | |||
| 735 | return err; | 767 | return err; |
| 736 | } | 768 | } |
| 737 | 769 | ||
| 738 | static inline int policy_to_flow_dir(int dir) | ||
| 739 | { | ||
| 740 | if (XFRM_POLICY_IN == FLOW_DIR_IN && | ||
| 741 | XFRM_POLICY_OUT == FLOW_DIR_OUT && | ||
| 742 | XFRM_POLICY_FWD == FLOW_DIR_FWD) | ||
| 743 | return dir; | ||
| 744 | switch (dir) { | ||
| 745 | default: | ||
| 746 | case XFRM_POLICY_IN: | ||
| 747 | return FLOW_DIR_IN; | ||
| 748 | case XFRM_POLICY_OUT: | ||
| 749 | return FLOW_DIR_OUT; | ||
| 750 | case XFRM_POLICY_FWD: | ||
| 751 | return FLOW_DIR_FWD; | ||
| 752 | }; | ||
| 753 | } | ||
| 754 | 770 | ||
| 755 | static int stale_bundle(struct dst_entry *dst); | 771 | static int stale_bundle(struct dst_entry *dst); |
| 756 | 772 | ||
| @@ -769,19 +785,20 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
| 769 | int err; | 785 | int err; |
| 770 | u32 genid; | 786 | u32 genid; |
| 771 | u16 family = dst_orig->ops->family; | 787 | u16 family = dst_orig->ops->family; |
| 788 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | ||
| 789 | u32 sk_sid = security_sk_sid(sk, fl, dir); | ||
| 772 | restart: | 790 | restart: |
| 773 | genid = atomic_read(&flow_cache_genid); | 791 | genid = atomic_read(&flow_cache_genid); |
| 774 | policy = NULL; | 792 | policy = NULL; |
| 775 | if (sk && sk->sk_policy[1]) | 793 | if (sk && sk->sk_policy[1]) |
| 776 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | 794 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid); |
| 777 | 795 | ||
| 778 | if (!policy) { | 796 | if (!policy) { |
| 779 | /* To accelerate a bit... */ | 797 | /* To accelerate a bit... */ |
| 780 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 798 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) |
| 781 | return 0; | 799 | return 0; |
| 782 | 800 | ||
| 783 | policy = flow_cache_lookup(fl, family, | 801 | policy = flow_cache_lookup(fl, sk_sid, family, dir, |
| 784 | policy_to_flow_dir(XFRM_POLICY_OUT), | ||
| 785 | xfrm_policy_lookup); | 802 | xfrm_policy_lookup); |
| 786 | } | 803 | } |
| 787 | 804 | ||
| @@ -962,16 +979,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 962 | { | 979 | { |
| 963 | struct xfrm_policy *pol; | 980 | struct xfrm_policy *pol; |
| 964 | struct flowi fl; | 981 | struct flowi fl; |
| 982 | u8 fl_dir = policy_to_flow_dir(dir); | ||
| 983 | u32 sk_sid; | ||
| 965 | 984 | ||
| 966 | if (_decode_session(skb, &fl, family) < 0) | 985 | if (_decode_session(skb, &fl, family) < 0) |
| 967 | return 0; | 986 | return 0; |
| 968 | 987 | ||
| 988 | sk_sid = security_sk_sid(sk, &fl, fl_dir); | ||
| 989 | |||
| 969 | /* First, check used SA against their selectors. */ | 990 | /* First, check used SA against their selectors. */ |
| 970 | if (skb->sp) { | 991 | if (skb->sp) { |
| 971 | int i; | 992 | int i; |
| 972 | 993 | ||
| 973 | for (i=skb->sp->len-1; i>=0; i--) { | 994 | for (i=skb->sp->len-1; i>=0; i--) { |
| 974 | struct sec_decap_state *xvec = &(skb->sp->x[i]); | 995 | struct sec_decap_state *xvec = &(skb->sp->x[i]); |
| 975 | if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) | 996 | if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) |
| 976 | return 0; | 997 | return 0; |
| 977 | 998 | ||
| @@ -986,11 +1007,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 986 | 1007 | ||
| 987 | pol = NULL; | 1008 | pol = NULL; |
| 988 | if (sk && sk->sk_policy[dir]) | 1009 | if (sk && sk->sk_policy[dir]) |
| 989 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); | 1010 | pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid); |
| 990 | 1011 | ||
| 991 | if (!pol) | 1012 | if (!pol) |
| 992 | pol = flow_cache_lookup(&fl, family, | 1013 | pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir, |
| 993 | policy_to_flow_dir(dir), | ||
| 994 | xfrm_policy_lookup); | 1014 | xfrm_policy_lookup); |
| 995 | 1015 | ||
| 996 | if (!pol) | 1016 | if (!pol) |
