The current secure allocator uses mlock a lot, pretty much on a per-page granularity.
The secure allocator makes use of a LockedPageManager to keep track of locked an non-locked pages. It locks the pages returned by the system allocator and unlocks them when no ‘secure’ allocations are on that page anymore.
It would be preferable to use a pool-based system, which pre-allocates areas of mlocked memory and deals these out as necessary.
The uses of SecureAllocator are:
- SecureString (string, used for wallet passphrases in CWallet interface).
- CKeyingMaterial (vector<char>, used for CCrypter interface and to store the master key in CCryptoKeyStore object).
- CPrivKey (used to store wallet keys)
The allocation pattern for these three is different
- SecureString
- is only used for small periods (argument passing).
- never stored for longer spans of time.
- allocated infrequently and not in performance-critical places
- dynamically-sized array of char
- CKeyingMaterial
- is used for argument passing, and one of these is stored for a longer time for locked wallets
- allocated infrequently and not in performance-critical places
- dynamically-sized array of char
- CPrivkey, on the other hand
- is allocated and deallocated frequently when loading a wallet or when generating large amounts of keys (for the keypool)
- usually they are only allocated and stored, though deallocation happens when these objects are copied around, for example as return values
- fixed-size objects
As the CPrivKey allocation pattern is the only one that causes performance issues and it requires only fixed-size objects no arrays, a possible solution is to use a boost::pool of mlocked memory chunks for just these.