From 23f485a9fb8eedde6555a91d5d11776c3f1e3dbf Mon Sep 17 00:00:00 2001 From: svost Date: Tue, 15 Feb 2022 22:15:22 +0300 Subject: [PATCH] Create allocatorc.cpp file --- CMakeLists.txt | 1 + src/CMakeLists.txt | 1 + src/allocators.cpp | 65 +++++++++++++++++++++++++++++++++ src/allocators.h | 103 +++++++++++++++++++++------------------------------- src/crypter.h | 8 ++-- src/util.cpp | 2 - 6 files changed, 112 insertions(+), 68 deletions(-) create mode 100644 src/allocators.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8746d69..036024d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,7 @@ set(generic_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingfilterproxy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingtablemodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/qt/mintingview.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/allocators.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/bignum.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/coincontrol.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/kernelrecord.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a088b3f..74969fe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,6 +78,7 @@ endif() set(generic_sources ${CMAKE_CURRENT_SOURCE_DIR}/addrman.cpp ${CMAKE_CURRENT_SOURCE_DIR}/alert.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/allocators.cpp ${CMAKE_CURRENT_SOURCE_DIR}/base58.cpp ${CMAKE_CURRENT_SOURCE_DIR}/bignum.cpp ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinrpc.cpp diff --git a/src/allocators.cpp b/src/allocators.cpp new file mode 100644 index 0000000..5e3ac7f --- /dev/null +++ b/src/allocators.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2009-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "allocators.h" + +#ifdef WIN32 +#if (_WIN32_WINNT != _WIN32_WINNT_WIN7) +#define _WIN32_WINNT 0x601 +#endif +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +// This is used to attempt to keep keying material out of swap +// Note that VirtualLock does not provide this as a guarantee on Windows, +// but, in practice, memory that has been VirtualLock'd almost never gets written to +// the pagefile except in rare circumstances where memory is extremely low. +#else +#include +#include // for PAGESIZE +#include // for sysconf +#endif + +LockedPageManager* LockedPageManager::_instance = nullptr; +std::once_flag LockedPageManager::init_flag{}; + +/** Determine system page size in bytes */ +static inline size_t GetSystemPageSize() +{ + size_t page_size; +#if defined(WIN32) + SYSTEM_INFO sSysInfo; + GetSystemInfo(&sSysInfo); + page_size = sSysInfo.dwPageSize; +#elif defined(PAGESIZE) // defined in limits.h + page_size = PAGESIZE; +#else // assume some POSIX OS + page_size = sysconf(_SC_PAGESIZE); +#endif + return page_size; +} + +bool MemoryPageLocker::Lock(const void *addr, size_t len) +{ +#ifdef WIN32 + return VirtualLock(const_cast(addr), len) != 0; +#else + return mlock(addr, len) == 0; +#endif +} + +bool MemoryPageLocker::Unlock(const void *addr, size_t len) +{ +#ifdef WIN32 + return VirtualUnlock(const_cast(addr), len) != 0; +#else + return munlock(addr, len) == 0; +#endif +} + +LockedPageManager::LockedPageManager(): LockedPageManagerBase(GetSystemPageSize()) +{ +} diff --git a/src/allocators.h b/src/allocators.h index 51bc73e..484d1b8 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -14,25 +14,6 @@ #include #include -#ifdef WIN32 -#if (_WIN32_WINNT != _WIN32_WINNT_WIN7) -#define _WIN32_WINNT 0x601 -#endif -#define WIN32_LEAN_AND_MEAN 1 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -// This is used to attempt to keep keying material out of swap -// Note that VirtualLock does not provide this as a guarantee on Windows, -// but, in practice, memory that has been VirtualLock'd almost never gets written to -// the pagefile except in rare circumstances where memory is extremely low. -#else -#include -#include // for PAGESIZE -#include // for sysconf -#endif - /** * Thread-safe class to keep track of locked (ie, non-swappable) memory pages. * @@ -55,6 +36,11 @@ public: page_mask = ~(page_size - 1); } + ~LockedPageManagerBase() + { + assert(this->GetLockedPageCount() == 0); + } + // For all pages in affected range, increase lock count void LockRange(void *p, size_t size) { @@ -117,22 +103,6 @@ private: Histogram histogram; }; -/** Determine system page size in bytes */ -static inline size_t GetSystemPageSize() -{ - size_t page_size; -#if defined(WIN32) - SYSTEM_INFO sSysInfo; - GetSystemInfo(&sSysInfo); - page_size = sSysInfo.dwPageSize; -#elif defined(PAGESIZE) // defined in limits.h - page_size = PAGESIZE; -#else // assume some POSIX OS - page_size = sysconf(_SC_PAGESIZE); -#endif - return page_size; -} - /** * OS-dependent memory page locking/unlocking. * Defined as policy class to make stubbing for test possible. @@ -143,39 +113,48 @@ public: /** Lock memory pages. * addr and len must be a multiple of the system page size */ - bool Lock(const void *addr, size_t len) - { -#ifdef WIN32 - return VirtualLock(const_cast(addr), len) != 0; -#else - return mlock(addr, len) == 0; -#endif - } + bool Lock(const void *addr, size_t len); /** Unlock memory pages. * addr and len must be a multiple of the system page size */ - bool Unlock(const void *addr, size_t len) - { -#ifdef WIN32 - return VirtualUnlock(const_cast(addr), len) != 0; -#else - return munlock(addr, len) == 0; -#endif - } + bool Unlock(const void *addr, size_t len); }; /** * Singleton class to keep track of locked (ie, non-swappable) memory pages, for use in * std::allocator templates. - */ + * + * Some implementations of the STL allocate memory in some constructors (i.e., see + * MSVC's vector implementation where it allocates 1 byte of memory in the allocator.) + * Due to the unpredictable order of static initializers, we have to make sure the + * LockedPageManager instance exists before any other STL-based objects that use + * secure_allocator are created. So instead of having LockedPageManager also be + * static-intialized, it is created on demand. +*/ class LockedPageManager: public LockedPageManagerBase { public: - static LockedPageManager instance; // instantiated in util.cpp + static LockedPageManager& Instance() + { + std::call_once(LockedPageManager::init_flag, LockedPageManager::CreateInstance); + return *LockedPageManager::_instance; + } private: - LockedPageManager(): - LockedPageManagerBase(GetSystemPageSize()) - {} + LockedPageManager(); + + static void CreateInstance() + { + // Using a local static instance guarantees that the object is initialized + // when it's first needed and also deinitialized after all objects that use + // it are done with it. I can think of one unlikely scenario where we may + // have a static deinitialization order/problem, but the check in + // LockedPageManagerBase's destructor helps us detect if that ever happens. + static LockedPageManager instance; + LockedPageManager::_instance = &instance; + } + + static LockedPageManager* _instance; + static std::once_flag init_flag; }; // @@ -202,21 +181,21 @@ struct secure_allocator : public std::allocator template struct rebind { typedef secure_allocator<_Other> other; }; - T* allocate(std::size_t n, const void *hint = 0) + T* allocate(std::size_t n, const void *hint = nullptr) { T *p; p = std::allocator::allocate(n, hint); - if (p != NULL) - LockedPageManager::instance.LockRange(p, sizeof(T) * n); + if (p != nullptr) + LockedPageManager::Instance().LockRange(p, sizeof(T) * n); return p; } void deallocate(T* p, std::size_t n) { - if (p != NULL) + if (p != nullptr) { OPENSSL_cleanse(p, sizeof(T) * n); - LockedPageManager::instance.UnlockRange(p, sizeof(T) * n); + LockedPageManager::Instance().UnlockRange(p, sizeof(T) * n); } std::allocator::deallocate(p, n); } @@ -248,7 +227,7 @@ struct zero_after_free_allocator : public std::allocator void deallocate(T* p, std::size_t n) { - if (p != NULL) + if (p != nullptr) OPENSSL_cleanse(p, sizeof(T) * n); std::allocator::deallocate(p, n); } diff --git a/src/crypter.h b/src/crypter.h index 733d9a3..20208e9 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -88,16 +88,16 @@ public: // Try to keep the key data out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap) // Note that this does nothing about suspend-to-disk (which will put all our key data on disk) // Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process. - LockedPageManager::instance.LockRange(&chKey[0], sizeof chKey); - LockedPageManager::instance.LockRange(&chIV[0], sizeof chIV); + LockedPageManager::Instance().LockRange(&chKey[0], sizeof chKey); + LockedPageManager::Instance().LockRange(&chIV[0], sizeof chIV); } ~CCrypter() { CleanKey(); - LockedPageManager::instance.UnlockRange(&chKey[0], sizeof chKey); - LockedPageManager::instance.UnlockRange(&chIV[0], sizeof chIV); + LockedPageManager::Instance().UnlockRange(&chKey[0], sizeof chKey); + LockedPageManager::Instance().UnlockRange(&chIV[0], sizeof chIV); } }; diff --git a/src/util.cpp b/src/util.cpp index ff99c1f..58cee1a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -79,8 +79,6 @@ void locking_callback(int mode, int i, const char* file, int line) } } -LockedPageManager LockedPageManager::instance; - // Init class CInit { -- 1.7.1