[IPSEC]: Fix policy updates missed by sockets
The problem is that when new policies are inserted, sockets do not see the update (but all new route lookups do). This bug is related to the SA insertion stale route issue solved recently, and this policy visibility problem can be fixed in a similar way. The fix is to flush out the bundles of all policies deeper than the policy being inserted. Consider beginning state of "outgoing" direction policy list: policy A --> policy B --> policy C --> policy D First, realize that inserting a policy into a list only potentially changes IPSEC routes for that direction. Therefore we need not bother considering the policies for other directions. We need only consider the existing policies in the list we are doing the inserting. Consider new policy "B'", inserted after B. policy A --> policy B --> policy B' --> policy C --> policy D Two rules: 1) If policy A or policy B matched before the insertion, they appear before B' and thus would still match after inserting B' 2) Policy C and D, now "shadowed" and after policy B', potentially contain stale routes because policy B' might be selected instead of them. Therefore we only need flush routes assosciated with policies appearing after a newly inserted policy, if any. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4c7e689502
commit
9b78a82c1c
1 changed files with 29 additions and 1 deletions
|
@ -346,6 +346,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
|
|||
struct xfrm_policy *pol, **p;
|
||||
struct xfrm_policy *delpol = NULL;
|
||||
struct xfrm_policy **newpos = NULL;
|
||||
struct dst_entry *gc_list;
|
||||
|
||||
write_lock_bh(&xfrm_policy_lock);
|
||||
for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) {
|
||||
|
@ -381,9 +382,36 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
|
|||
xfrm_pol_hold(policy);
|
||||
write_unlock_bh(&xfrm_policy_lock);
|
||||
|
||||
if (delpol) {
|
||||
if (delpol)
|
||||
xfrm_policy_kill(delpol);
|
||||
|
||||
read_lock_bh(&xfrm_policy_lock);
|
||||
gc_list = NULL;
|
||||
for (policy = policy->next; policy; policy = policy->next) {
|
||||
struct dst_entry *dst;
|
||||
|
||||
write_lock(&policy->lock);
|
||||
dst = policy->bundles;
|
||||
if (dst) {
|
||||
struct dst_entry *tail = dst;
|
||||
while (tail->next)
|
||||
tail = tail->next;
|
||||
tail->next = gc_list;
|
||||
gc_list = dst;
|
||||
|
||||
policy->bundles = NULL;
|
||||
}
|
||||
write_unlock(&policy->lock);
|
||||
}
|
||||
read_unlock_bh(&xfrm_policy_lock);
|
||||
|
||||
while (gc_list) {
|
||||
struct dst_entry *dst = gc_list;
|
||||
|
||||
gc_list = dst->next;
|
||||
dst_free(dst);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(xfrm_policy_insert);
|
||||
|
|
Loading…
Reference in a new issue