/tmp/bitcoin/src/support/allocators/secure.h
Line | Count | Source |
1 | | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | | // Copyright (c) 2009-present The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #ifndef BITCOIN_SUPPORT_ALLOCATORS_SECURE_H |
7 | | #define BITCOIN_SUPPORT_ALLOCATORS_SECURE_H |
8 | | |
9 | | #include <support/lockedpool.h> |
10 | | #include <support/cleanse.h> |
11 | | |
12 | | #include <memory> |
13 | | #include <string> |
14 | | |
15 | | // |
16 | | // Allocator that locks its contents from being paged |
17 | | // out of memory and clears its contents before deletion. |
18 | | // |
19 | | template <typename T> |
20 | | struct secure_allocator { |
21 | | using value_type = T; |
22 | | |
23 | | secure_allocator() = default; |
24 | | template <typename U> |
25 | | secure_allocator(const secure_allocator<U>&) noexcept {} |
26 | | |
27 | | T* allocate(std::size_t n) |
28 | 415k | { |
29 | 415k | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); |
30 | 415k | if (!allocation) { |
31 | 0 | throw std::bad_alloc(); |
32 | 0 | } |
33 | 415k | return allocation; |
34 | 415k | } secure_allocator<std::array<unsigned char, 32ul>>::allocate(unsigned long) Line | Count | Source | 28 | 254k | { | 29 | 254k | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); | 30 | 254k | if (!allocation) { | 31 | 0 | throw std::bad_alloc(); | 32 | 0 | } | 33 | 254k | return allocation; | 34 | 254k | } |
secure_allocator<std::array<unsigned char, 96ul>>::allocate(unsigned long) Line | Count | Source | 28 | 1.38k | { | 29 | 1.38k | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); | 30 | 1.38k | if (!allocation) { | 31 | 0 | throw std::bad_alloc(); | 32 | 0 | } | 33 | 1.38k | return allocation; | 34 | 1.38k | } |
secure_allocator<unsigned char>::allocate(unsigned long) Line | Count | Source | 28 | 147k | { | 29 | 147k | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); | 30 | 147k | if (!allocation) { | 31 | 0 | throw std::bad_alloc(); | 32 | 0 | } | 33 | 147k | return allocation; | 34 | 147k | } |
secure_allocator<char>::allocate(unsigned long) Line | Count | Source | 28 | 776 | { | 29 | 776 | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); | 30 | 776 | if (!allocation) { | 31 | 0 | throw std::bad_alloc(); | 32 | 0 | } | 33 | 776 | return allocation; | 34 | 776 | } |
secure_allocator<secp256k1_musig_secnonce>::allocate(unsigned long) Line | Count | Source | 28 | 79 | { | 29 | 79 | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); | 30 | 79 | if (!allocation) { | 31 | 0 | throw std::bad_alloc(); | 32 | 0 | } | 33 | 79 | return allocation; | 34 | 79 | } |
random.cpp:secure_allocator<(anonymous namespace)::RNGState>::allocate(unsigned long) Line | Count | Source | 28 | 1.18k | { | 29 | 1.18k | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); | 30 | 1.18k | if (!allocation) { | 31 | 0 | throw std::bad_alloc(); | 32 | 0 | } | 33 | 1.18k | return allocation; | 34 | 1.18k | } |
secure_allocator<AES256_ctx>::allocate(unsigned long) Line | Count | Source | 28 | 10.1k | { | 29 | 10.1k | T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n)); | 30 | 10.1k | if (!allocation) { | 31 | 0 | throw std::bad_alloc(); | 32 | 0 | } | 33 | 10.1k | return allocation; | 34 | 10.1k | } |
|
35 | | |
36 | | void deallocate(T* p, std::size_t n) |
37 | 415k | { |
38 | 415k | if (p != nullptr) { |
39 | 415k | memory_cleanse(p, sizeof(T) * n); |
40 | 415k | } |
41 | 415k | LockedPoolManager::Instance().free(p); |
42 | 415k | } secure_allocator<std::array<unsigned char, 32ul>>::deallocate(std::array<unsigned char, 32ul>*, unsigned long) Line | Count | Source | 37 | 254k | { | 38 | 254k | if (p != nullptr) { | 39 | 254k | memory_cleanse(p, sizeof(T) * n); | 40 | 254k | } | 41 | 254k | LockedPoolManager::Instance().free(p); | 42 | 254k | } |
secure_allocator<std::array<unsigned char, 96ul>>::deallocate(std::array<unsigned char, 96ul>*, unsigned long) Line | Count | Source | 37 | 1.38k | { | 38 | 1.38k | if (p != nullptr) { | 39 | 1.38k | memory_cleanse(p, sizeof(T) * n); | 40 | 1.38k | } | 41 | 1.38k | LockedPoolManager::Instance().free(p); | 42 | 1.38k | } |
secure_allocator<unsigned char>::deallocate(unsigned char*, unsigned long) Line | Count | Source | 37 | 147k | { | 38 | 147k | if (p != nullptr) { | 39 | 147k | memory_cleanse(p, sizeof(T) * n); | 40 | 147k | } | 41 | 147k | LockedPoolManager::Instance().free(p); | 42 | 147k | } |
secure_allocator<char>::deallocate(char*, unsigned long) Line | Count | Source | 37 | 776 | { | 38 | 776 | if (p != nullptr) { | 39 | 776 | memory_cleanse(p, sizeof(T) * n); | 40 | 776 | } | 41 | 776 | LockedPoolManager::Instance().free(p); | 42 | 776 | } |
secure_allocator<secp256k1_musig_secnonce>::deallocate(secp256k1_musig_secnonce*, unsigned long) Line | Count | Source | 37 | 79 | { | 38 | 79 | if (p != nullptr) { | 39 | 79 | memory_cleanse(p, sizeof(T) * n); | 40 | 79 | } | 41 | 79 | LockedPoolManager::Instance().free(p); | 42 | 79 | } |
random.cpp:secure_allocator<(anonymous namespace)::RNGState>::deallocate((anonymous namespace)::RNGState*, unsigned long) Line | Count | Source | 37 | 1.18k | { | 38 | 1.18k | if (p != nullptr) { | 39 | 1.18k | memory_cleanse(p, sizeof(T) * n); | 40 | 1.18k | } | 41 | 1.18k | LockedPoolManager::Instance().free(p); | 42 | 1.18k | } |
secure_allocator<AES256_ctx>::deallocate(AES256_ctx*, unsigned long) Line | Count | Source | 37 | 10.1k | { | 38 | 10.1k | if (p != nullptr) { | 39 | 10.1k | memory_cleanse(p, sizeof(T) * n); | 40 | 10.1k | } | 41 | 10.1k | LockedPoolManager::Instance().free(p); | 42 | 10.1k | } |
|
43 | | |
44 | | template <typename U> |
45 | | friend bool operator==(const secure_allocator&, const secure_allocator<U>&) noexcept |
46 | 0 | { |
47 | 0 | return true; |
48 | 0 | } Unexecuted instantiation: bool operator==<char>(secure_allocator<char> const&, secure_allocator<char> const&) Unexecuted instantiation: bool operator==<unsigned char>(secure_allocator<unsigned char> const&, secure_allocator<unsigned char> const&) |
49 | | }; |
50 | | |
51 | | // This is exactly like std::string, but with a custom allocator. |
52 | | // TODO: Consider finding a way to make incoming RPC request.params[i] mlock()ed as well |
53 | | typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString; |
54 | | |
55 | | template<typename T> |
56 | | struct SecureUniqueDeleter { |
57 | 255k | void operator()(T* t) noexcept { |
58 | 255k | secure_allocator<T>().deallocate(t, 1); |
59 | 255k | } SecureUniqueDeleter<std::array<unsigned char, 32ul>>::operator()(std::array<unsigned char, 32ul>*) Line | Count | Source | 57 | 254k | void operator()(T* t) noexcept { | 58 | 254k | secure_allocator<T>().deallocate(t, 1); | 59 | 254k | } |
SecureUniqueDeleter<std::array<unsigned char, 96ul>>::operator()(std::array<unsigned char, 96ul>*) Line | Count | Source | 57 | 1.38k | void operator()(T* t) noexcept { | 58 | 1.38k | secure_allocator<T>().deallocate(t, 1); | 59 | 1.38k | } |
SecureUniqueDeleter<secp256k1_musig_secnonce>::operator()(secp256k1_musig_secnonce*) Line | Count | Source | 57 | 79 | void operator()(T* t) noexcept { | 58 | 79 | secure_allocator<T>().deallocate(t, 1); | 59 | 79 | } |
|
60 | | }; |
61 | | |
62 | | template<typename T> |
63 | | using secure_unique_ptr = std::unique_ptr<T, SecureUniqueDeleter<T>>; |
64 | | |
65 | | template<typename T, typename... Args> |
66 | | secure_unique_ptr<T> make_secure_unique(Args&&... as) |
67 | 255k | { |
68 | 255k | T* p = secure_allocator<T>().allocate(1); |
69 | | |
70 | | // initialize in place, and return as secure_unique_ptr |
71 | 255k | try { |
72 | 255k | return secure_unique_ptr<T>(new (p) T(std::forward<Args>(as)...)); |
73 | 255k | } catch (...) { |
74 | 0 | secure_allocator<T>().deallocate(p, 1); |
75 | 0 | throw; |
76 | 0 | } |
77 | 255k | } std::unique_ptr<std::array<unsigned char, 32ul>, SecureUniqueDeleter<std::array<unsigned char, 32ul>>> make_secure_unique<std::array<unsigned char, 32ul>>() Line | Count | Source | 67 | 254k | { | 68 | 254k | T* p = secure_allocator<T>().allocate(1); | 69 | | | 70 | | // initialize in place, and return as secure_unique_ptr | 71 | 254k | try { | 72 | 254k | return secure_unique_ptr<T>(new (p) T(std::forward<Args>(as)...)); | 73 | 254k | } catch (...) { | 74 | 0 | secure_allocator<T>().deallocate(p, 1); | 75 | 0 | throw; | 76 | 0 | } | 77 | 254k | } |
std::unique_ptr<std::array<unsigned char, 96ul>, SecureUniqueDeleter<std::array<unsigned char, 96ul>>> make_secure_unique<std::array<unsigned char, 96ul>>() Line | Count | Source | 67 | 1.38k | { | 68 | 1.38k | T* p = secure_allocator<T>().allocate(1); | 69 | | | 70 | | // initialize in place, and return as secure_unique_ptr | 71 | 1.38k | try { | 72 | 1.38k | return secure_unique_ptr<T>(new (p) T(std::forward<Args>(as)...)); | 73 | 1.38k | } catch (...) { | 74 | 0 | secure_allocator<T>().deallocate(p, 1); | 75 | 0 | throw; | 76 | 0 | } | 77 | 1.38k | } |
std::unique_ptr<secp256k1_musig_secnonce, SecureUniqueDeleter<secp256k1_musig_secnonce>> make_secure_unique<secp256k1_musig_secnonce>() Line | Count | Source | 67 | 79 | { | 68 | 79 | T* p = secure_allocator<T>().allocate(1); | 69 | | | 70 | | // initialize in place, and return as secure_unique_ptr | 71 | 79 | try { | 72 | 79 | return secure_unique_ptr<T>(new (p) T(std::forward<Args>(as)...)); | 73 | 79 | } catch (...) { | 74 | 0 | secure_allocator<T>().deallocate(p, 1); | 75 | 0 | throw; | 76 | 0 | } | 77 | 79 | } |
|
78 | | |
79 | | #endif // BITCOIN_SUPPORT_ALLOCATORS_SECURE_H |