Page MenuHomeFreeBSD

Fix memory leak and several races in IPsec policies management code
ClosedPublic

Authored by ae on Feb 20 2015, 4:56 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Nov 12, 2:01 AM
Unknown Object (File)
Wed, Nov 6, 8:38 AM
Unknown Object (File)
Sun, Nov 3, 3:01 PM
Unknown Object (File)
Sun, Nov 3, 3:01 PM
Unknown Object (File)
Sun, Nov 3, 2:42 PM
Unknown Object (File)
Oct 22 2024, 7:01 AM
Unknown Object (File)
Sep 18 2024, 1:22 PM
Unknown Object (File)
Sep 18 2024, 1:22 PM
Subscribers
None

Details

Reviewers
hrs
Group Reviewers
network
Summary

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:

  1. vmstat -m | grep ipsec
  2. setkey -c spdadd 192.168.0.11 192.168.0.3 any -P out ipsec esp/transport//default;
  3. vmstat -m | grep ipsec
  4. setkey -c spddelete 192.168.0.11 192.168.0.3 any -P out;
  5. 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.

Test Plan

setkey with spdadd and spddelete works as expected. Descibed races are hard to get...

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
No Lint Coverage
Unit
No Test Coverage

Event Timeline

ae retitled this revision from to Fix memory leak and several races in IPsec policies management code.
ae updated this object.
ae edited the test plan for this revision. (Show Details)
ae added a reviewer: network.
hrs added a reviewer: hrs.
hrs edited edge metadata.
This revision is now accepted and ready to land.Feb 21 2015, 6:13 PM