diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-01-16 19:52:02 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-01-23 23:25:51 -0500 |
commit | a6c7ab55dda3e16ab5a3cf6f39585aee5876ac3a (patch) | |
tree | 2ad7ed20bcf18bf1ff8b9354ec0a8f498627c1eb /net/xfrm/xfrm_policy.c | |
parent | 8f1adb5f27d352c776ac34648cc277d1f8199dba (diff) |
[IPSEC]: Policy list disorder
The recent hashing introduced an off-by-one bug in policy list insertion.
Instead of adding after the last entry with a lesser or equal priority,
we're adding after the successor of that entry.
This patch fixes this and also adds a warning if we detect a duplicate
entry in the policy list. This should never happen due to this if clause.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 16 |
1 files changed, 5 insertions, 11 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index bebd40e5a62e..b7e537fe2d75 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -650,19 +650,18 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
650 | struct xfrm_policy *pol; | 650 | struct xfrm_policy *pol; |
651 | struct xfrm_policy *delpol; | 651 | struct xfrm_policy *delpol; |
652 | struct hlist_head *chain; | 652 | struct hlist_head *chain; |
653 | struct hlist_node *entry, *newpos, *last; | 653 | struct hlist_node *entry, *newpos; |
654 | struct dst_entry *gc_list; | 654 | struct dst_entry *gc_list; |
655 | 655 | ||
656 | write_lock_bh(&xfrm_policy_lock); | 656 | write_lock_bh(&xfrm_policy_lock); |
657 | chain = policy_hash_bysel(&policy->selector, policy->family, dir); | 657 | chain = policy_hash_bysel(&policy->selector, policy->family, dir); |
658 | delpol = NULL; | 658 | delpol = NULL; |
659 | newpos = NULL; | 659 | newpos = NULL; |
660 | last = NULL; | ||
661 | hlist_for_each_entry(pol, entry, chain, bydst) { | 660 | hlist_for_each_entry(pol, entry, chain, bydst) { |
662 | if (!delpol && | 661 | if (pol->type == policy->type && |
663 | pol->type == policy->type && | ||
664 | !selector_cmp(&pol->selector, &policy->selector) && | 662 | !selector_cmp(&pol->selector, &policy->selector) && |
665 | xfrm_sec_ctx_match(pol->security, policy->security)) { | 663 | xfrm_sec_ctx_match(pol->security, policy->security) && |
664 | !WARN_ON(delpol)) { | ||
666 | if (excl) { | 665 | if (excl) { |
667 | write_unlock_bh(&xfrm_policy_lock); | 666 | write_unlock_bh(&xfrm_policy_lock); |
668 | return -EEXIST; | 667 | return -EEXIST; |
@@ -671,17 +670,12 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
671 | if (policy->priority > pol->priority) | 670 | if (policy->priority > pol->priority) |
672 | continue; | 671 | continue; |
673 | } else if (policy->priority >= pol->priority) { | 672 | } else if (policy->priority >= pol->priority) { |
674 | last = &pol->bydst; | 673 | newpos = &pol->bydst; |
675 | continue; | 674 | continue; |
676 | } | 675 | } |
677 | if (!newpos) | ||
678 | newpos = &pol->bydst; | ||
679 | if (delpol) | 676 | if (delpol) |
680 | break; | 677 | break; |
681 | last = &pol->bydst; | ||
682 | } | 678 | } |
683 | if (!newpos) | ||
684 | newpos = last; | ||
685 | if (newpos) | 679 | if (newpos) |
686 | hlist_add_after(newpos, &policy->bydst); | 680 | hlist_add_after(newpos, &policy->bydst); |
687 | else | 681 | else |