aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 0ecb16a9a883..34a5ef8316e7 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -556,6 +556,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
556 struct hlist_head *chain; 556 struct hlist_head *chain;
557 struct hlist_node *entry, *newpos; 557 struct hlist_node *entry, *newpos;
558 struct dst_entry *gc_list; 558 struct dst_entry *gc_list;
559 u32 mark = policy->mark.v & policy->mark.m;
559 560
560 write_lock_bh(&xfrm_policy_lock); 561 write_lock_bh(&xfrm_policy_lock);
561 chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); 562 chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
@@ -564,6 +565,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
564 hlist_for_each_entry(pol, entry, chain, bydst) { 565 hlist_for_each_entry(pol, entry, chain, bydst) {
565 if (pol->type == policy->type && 566 if (pol->type == policy->type &&
566 !selector_cmp(&pol->selector, &policy->selector) && 567 !selector_cmp(&pol->selector, &policy->selector) &&
568 (mark & pol->mark.m) == pol->mark.v &&
567 xfrm_sec_ctx_match(pol->security, policy->security) && 569 xfrm_sec_ctx_match(pol->security, policy->security) &&
568 !WARN_ON(delpol)) { 570 !WARN_ON(delpol)) {
569 if (excl) { 571 if (excl) {
@@ -635,8 +637,8 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
635} 637}
636EXPORT_SYMBOL(xfrm_policy_insert); 638EXPORT_SYMBOL(xfrm_policy_insert);
637 639
638struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, 640struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
639 struct xfrm_selector *sel, 641 int dir, struct xfrm_selector *sel,
640 struct xfrm_sec_ctx *ctx, int delete, 642 struct xfrm_sec_ctx *ctx, int delete,
641 int *err) 643 int *err)
642{ 644{
@@ -650,6 +652,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir,
650 ret = NULL; 652 ret = NULL;
651 hlist_for_each_entry(pol, entry, chain, bydst) { 653 hlist_for_each_entry(pol, entry, chain, bydst) {
652 if (pol->type == type && 654 if (pol->type == type &&
655 (mark & pol->mark.m) == pol->mark.v &&
653 !selector_cmp(sel, &pol->selector) && 656 !selector_cmp(sel, &pol->selector) &&
654 xfrm_sec_ctx_match(ctx, pol->security)) { 657 xfrm_sec_ctx_match(ctx, pol->security)) {
655 xfrm_pol_hold(pol); 658 xfrm_pol_hold(pol);
@@ -676,8 +679,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir,
676} 679}
677EXPORT_SYMBOL(xfrm_policy_bysel_ctx); 680EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
678 681
679struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id, 682struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
680 int delete, int *err) 683 int dir, u32 id, int delete, int *err)
681{ 684{
682 struct xfrm_policy *pol, *ret; 685 struct xfrm_policy *pol, *ret;
683 struct hlist_head *chain; 686 struct hlist_head *chain;
@@ -692,7 +695,8 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id,
692 chain = net->xfrm.policy_byidx + idx_hash(net, id); 695 chain = net->xfrm.policy_byidx + idx_hash(net, id);
693 ret = NULL; 696 ret = NULL;
694 hlist_for_each_entry(pol, entry, chain, byidx) { 697 hlist_for_each_entry(pol, entry, chain, byidx) {
695 if (pol->type == type && pol->index == id) { 698 if (pol->type == type && pol->index == id &&
699 (mark & pol->mark.m) == pol->mark.v) {
696 xfrm_pol_hold(pol); 700 xfrm_pol_hold(pol);
697 if (delete) { 701 if (delete) {
698 *err = security_xfrm_policy_delete( 702 *err = security_xfrm_policy_delete(
@@ -771,7 +775,8 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi
771 775
772int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) 776int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
773{ 777{
774 int dir, err = 0; 778 int dir, err = 0, cnt = 0;
779 struct xfrm_policy *dp;
775 780
776 write_lock_bh(&xfrm_policy_lock); 781 write_lock_bh(&xfrm_policy_lock);
777 782
@@ -789,8 +794,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
789 &net->xfrm.policy_inexact[dir], bydst) { 794 &net->xfrm.policy_inexact[dir], bydst) {
790 if (pol->type != type) 795 if (pol->type != type)
791 continue; 796 continue;
792 __xfrm_policy_unlink(pol, dir); 797 dp = __xfrm_policy_unlink(pol, dir);
793 write_unlock_bh(&xfrm_policy_lock); 798 write_unlock_bh(&xfrm_policy_lock);
799 if (dp)
800 cnt++;
794 801
795 xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, 802 xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
796 audit_info->sessionid, 803 audit_info->sessionid,
@@ -809,8 +816,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
809 bydst) { 816 bydst) {
810 if (pol->type != type) 817 if (pol->type != type)
811 continue; 818 continue;
812 __xfrm_policy_unlink(pol, dir); 819 dp = __xfrm_policy_unlink(pol, dir);
813 write_unlock_bh(&xfrm_policy_lock); 820 write_unlock_bh(&xfrm_policy_lock);
821 if (dp)
822 cnt++;
814 823
815 xfrm_audit_policy_delete(pol, 1, 824 xfrm_audit_policy_delete(pol, 1,
816 audit_info->loginuid, 825 audit_info->loginuid,
@@ -824,6 +833,8 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
824 } 833 }
825 834
826 } 835 }
836 if (!cnt)
837 err = -ESRCH;
827 atomic_inc(&flow_cache_genid); 838 atomic_inc(&flow_cache_genid);
828out: 839out:
829 write_unlock_bh(&xfrm_policy_lock); 840 write_unlock_bh(&xfrm_policy_lock);
@@ -909,6 +920,7 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,
909 int match, ret = -ESRCH; 920 int match, ret = -ESRCH;
910 921
911 if (pol->family != family || 922 if (pol->family != family ||
923 (fl->mark & pol->mark.m) != pol->mark.v ||
912 pol->type != type) 924 pol->type != type)
913 return ret; 925 return ret;
914 926
@@ -1033,6 +1045,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc
1033 int err = 0; 1045 int err = 0;
1034 1046
1035 if (match) { 1047 if (match) {
1048 if ((sk->sk_mark & pol->mark.m) != pol->mark.v) {
1049 pol = NULL;
1050 goto out;
1051 }
1036 err = security_xfrm_policy_lookup(pol->security, 1052 err = security_xfrm_policy_lookup(pol->security,
1037 fl->secid, 1053 fl->secid,
1038 policy_to_flow_dir(dir)); 1054 policy_to_flow_dir(dir));
@@ -1045,6 +1061,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc
1045 } else 1061 } else
1046 pol = NULL; 1062 pol = NULL;
1047 } 1063 }
1064out:
1048 read_unlock_bh(&xfrm_policy_lock); 1065 read_unlock_bh(&xfrm_policy_lock);
1049 return pol; 1066 return pol;
1050} 1067}
@@ -1137,6 +1154,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir)
1137 } 1154 }
1138 newp->lft = old->lft; 1155 newp->lft = old->lft;
1139 newp->curlft = old->curlft; 1156 newp->curlft = old->curlft;
1157 newp->mark = old->mark;
1140 newp->action = old->action; 1158 newp->action = old->action;
1141 newp->flags = old->flags; 1159 newp->flags = old->flags;
1142 newp->xfrm_nr = old->xfrm_nr; 1160 newp->xfrm_nr = old->xfrm_nr;
@@ -2045,8 +2063,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
2045 int res; 2063 int res;
2046 2064
2047 if (xfrm_decode_session(skb, &fl, family) < 0) { 2065 if (xfrm_decode_session(skb, &fl, family) < 0) {
2048 /* XXX: we should have something like FWDHDRERROR here. */ 2066 XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR);
2049 XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
2050 return 0; 2067 return 0;
2051 } 2068 }
2052 2069
@@ -2421,19 +2438,19 @@ static int __net_init xfrm_statistics_init(struct net *net)
2421{ 2438{
2422 int rv; 2439 int rv;
2423 2440
2424 if (snmp_mib_init((void **)net->mib.xfrm_statistics, 2441 if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics,
2425 sizeof(struct linux_xfrm_mib)) < 0) 2442 sizeof(struct linux_xfrm_mib)) < 0)
2426 return -ENOMEM; 2443 return -ENOMEM;
2427 rv = xfrm_proc_init(net); 2444 rv = xfrm_proc_init(net);
2428 if (rv < 0) 2445 if (rv < 0)
2429 snmp_mib_free((void **)net->mib.xfrm_statistics); 2446 snmp_mib_free((void __percpu **)net->mib.xfrm_statistics);
2430 return rv; 2447 return rv;
2431} 2448}
2432 2449
2433static void xfrm_statistics_fini(struct net *net) 2450static void xfrm_statistics_fini(struct net *net)
2434{ 2451{
2435 xfrm_proc_fini(net); 2452 xfrm_proc_fini(net);
2436 snmp_mib_free((void **)net->mib.xfrm_statistics); 2453 snmp_mib_free((void __percpu **)net->mib.xfrm_statistics);
2437} 2454}
2438#else 2455#else
2439static int __net_init xfrm_statistics_init(struct net *net) 2456static int __net_init xfrm_statistics_init(struct net *net)