[XFRM]: Respect priority in policy lookups.
Even if we find an exact match in the hash table,
we must inspect the inexact list to look for a match
with a better priority.
Noticed by Masahide NAKAMURA <nakam@linux-ipv6.org>.
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b446ca3..1cf3209 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -908,6 +908,7 @@
xfrm_address_t *daddr, *saddr;
struct hlist_node *entry;
struct hlist_head *chain;
+ u32 priority = ~0U;
daddr = xfrm_flowi_daddr(fl, family);
saddr = xfrm_flowi_saddr(fl, family);
@@ -919,21 +920,21 @@
ret = NULL;
hlist_for_each_entry(pol, entry, chain, bydst) {
if (xfrm_policy_match(pol, fl, type, family, dir)) {
- xfrm_pol_hold(pol);
+ ret = pol;
+ priority = ret->priority;
+ break;
+ }
+ }
+ chain = &xfrm_policy_inexact[dir];
+ hlist_for_each_entry(pol, entry, chain, bydst) {
+ if (xfrm_policy_match(pol, fl, type, family, dir) &&
+ pol->priority < priority) {
ret = pol;
break;
}
}
- if (!ret) {
- chain = &xfrm_policy_inexact[dir];
- hlist_for_each_entry(pol, entry, chain, bydst) {
- if (xfrm_policy_match(pol, fl, type, family, dir)) {
- xfrm_pol_hold(pol);
- ret = pol;
- break;
- }
- }
- }
+ if (ret)
+ xfrm_pol_hold(ret);
read_unlock_bh(&xfrm_policy_lock);
return ret;