1 /* 2 * Derived from Botan's Mlock Allocator 3 * 4 * This is a more advanced base allocator. 5 * 6 * (C) 2012,2014 Jack Lloyd 7 * (C) 2014-2015 Etienne Cimon 8 * (C) 2014,2015 Etienne Cimon 9 * 10 * Distributed under the terms of the Simplified BSD License (see Botan's license.txt) 11 */ 12 module memutils.cryptosafe; 13 import memutils.constants; 14 static if (HasCryptoSafe): 15 pragma(msg, "Enhanced memory security is enabled."); 16 17 import memutils.allocators; 18 import memutils.securepool; 19 import memutils.debugger; 20 21 final class SecureAllocator(Base : Allocator) : Allocator 22 { 23 private: 24 Base m_secondary; 25 static if (HasSecurePool) { 26 27 __gshared SecurePool ms_zeroise; 28 __gshared bool ms_deinit; 29 shared static this() { 30 //logDebug("Shared static this() SecurePool"); 31 if (!ms_zeroise) ms_zeroise = new SecurePool(); 32 } 33 shared static ~this() { 34 if (ms_zeroise) { destroy(ms_zeroise); ms_zeroise = null; ms_deinit = true; } 35 } 36 } 37 38 public: 39 this() { 40 version(TLSGC) { } else { 41 if (!mtx) mtx = new Mutex; 42 } 43 static if (HasSecurePool) { 44 if (!ms_zeroise) ms_zeroise = new SecurePool(); 45 } 46 m_secondary = getAllocator!Base(); 47 } 48 49 void[] alloc(size_t n) 50 { 51 version(TLSGC) { } else { 52 mtx.lock_nothrow(); 53 scope(exit) mtx.unlock_nothrow(); 54 } 55 static if (HasSecurePool) { 56 //logDebug("CryptoSafe alloc ", n); 57 if (void[] p = ms_zeroise.alloc(n)) { 58 //logDebug("alloc P: ", p.length, " & ", p.ptr); 59 return p; 60 } 61 } 62 //logDebug("secondary alloc"); 63 void[] p = m_secondary.alloc(n); 64 65 //logDebug("FALLBACK alloc P: ", p.length, " & ", p.ptr); 66 return p; 67 } 68 69 void[] realloc(void[] mem, size_t n) 70 { 71 version(TLSGC) { } else { 72 mtx.lock_nothrow(); 73 scope(exit) mtx.unlock_nothrow(); 74 } 75 //logTrace("realloc P: ", mem.length, " & ", mem.ptr); 76 if (n <= mem.length) 77 return mem; 78 import core.stdc.string : memmove, memset; 79 80 static if (HasSecurePool) { 81 if (ms_zeroise.has(mem)) { 82 void[] p = ms_zeroise.alloc(n); 83 if (!p) 84 p = m_secondary.alloc(n); 85 memmove(p.ptr, mem.ptr, mem.length); 86 memset(mem.ptr, 0, mem.length); 87 ms_zeroise.free(mem); 88 return p; 89 } 90 } 91 92 return m_secondary.realloc(mem, n); 93 } 94 95 void free(void[] mem) 96 { 97 version(TLSGC) { } else { 98 mtx.lock_nothrow(); 99 scope(exit) mtx.unlock_nothrow(); 100 } 101 //logTrace("free P: ", mem.length, " & ", mem.ptr); 102 import core.stdc.string : memset; 103 bool skip_zero; 104 if (mem.length > 1024) { 105 skip_zero = true; 106 ubyte* ptr = cast(ubyte*)mem.ptr; 107 // check some random bytes for zero 108 size_t j; 109 foreach (i; 0 .. mem.length/128) { 110 if (ptr[j]+4 == 0 && ptr[j]+8 == 0 && ptr[j]+50 == 0 && ptr[j]+80 == 0) { 111 j += 128; 112 continue; 113 } 114 skip_zero = false; 115 break; 116 } 117 } 118 if (!skip_zero) 119 memset(mem.ptr, 0, mem.length); 120 static if (HasSecurePool) 121 if (ms_deinit || ms_zeroise.free(mem)) 122 return; 123 m_secondary.free(mem); 124 } 125 126 }