When we add new security policy, it has reference count == 1.
key_spddelete() and key_spddelete2() functions use key_getsp*() functions
to check that security policy exist. key_getsp*() functions return
structure referenced. So, when key_spddelete*() are going to free policy,
policy already has at least 2 references and after key_unlink() and KEY_FREESP()
one reference still be here. To fix this problem I added KEY_FREESP() call to the
key_unlink().
This can be reproduced with the following commands:
- vmstat -m | grep ipsec
- setkey -c spdadd 192.168.0.11 192.168.0.3 any -P out ipsec esp/transport//default;
- vmstat -m | grep ipsec
- setkey -c spddelete 192.168.0.11 192.168.0.3 any -P out;
- vmstat -m | grep ipsec
Second problem:
It is possible that two threads will try to delete the same security policy.
So, in the key_spddelete*() after getting pointer to security policy one thread
will call key_unlink() second time for the same security policy. This will lead to
kernel panic.
I resurrected the state field in the struct secpolicy, it will have ALIVE state
only when it linked to the chain. Now key_unlink() checks this field before
TAILQ_REMOVE(). Default security policy and those that contained in the PCB structure,
will have state DEAD == 0, so this protects us also from trying to remove them from the chain.
Another problem:
key_flush_spd() is called from callout and removes expired security policies.
It is possible in time between SPTREE_RUNLOCK() and KEY_FREESP(), another thread
will already remove this security policy. I added additional SP_ADDREF() to the policy
that we will remove after SPTREE_RUNLOCK().
Also I added the loop that sets state field to DEAD in the key_spdflush(). This will
protect us from the trying to unlink security policy after flushing.