I have the following class which is being compiled in Visual Studio 2015:
class MitigationPolicyChecker
{
public:
static auto& getInstance()
{
static MitigationPolicyChecker instance;
return instance;
}
MitigationPolicyChecker(MitigationPolicyChecker const&) = delete;
MitigationPolicyChecker(MitigationPolicyChecker&&) = delete;
MitigationPolicyChecker& operator=(MitigationPolicyChecker const&) = delete;
MitigationPolicyChecker& operator=(MitigationPolicyChecker&&) = delete;
bool IsDynamicCodeProhibited();
private:
MitigationPolicyChecker() = default;
~MitigationPolicyChecker() = default;
void GetDynamicCodePolicy();
bool m_bDynamicCodeProhibited = false;
};
The class is designed to run from DllMain and checks for a structure in NtDll's loaded image to check if a certain mitigation policy is enabled.
In rare cases (<0.0001% of times the dll is loaded) this singleton is causing the app to crash. However, the crash isn't related to what the class is trying to do or to the well known list of things which aren't permitted in DllMain (as far as I can tell). It's related to the instantiation of the singleton its self.
The call stack in WinDbg looks like this:
00 OurDll!MitigationPolicyChecker::getInstance+0x1a
02 OurDll!Initialize+0x79
03 OurDll!DllMain+0x1c9
04 OurDll!dllmain_dispatch+0x74
05 ntdll!LdrpRunInitializeRoutines+0x1fe
06 ntdll!LdrGetProcedureAddressEx+0x2aa
07 ntdll!LdrpCorInitialize+0x1a1
08 ntdll!LdrpInitializeProcess+0x1816
09 ntdll! ?? ::FNODOBFM::`string'+0x22790
0a ntdll!LdrInitializeThunk+0xe
An access violation occurs on the line static MitigationPolicyChecker instance
And the crashing assembly line is the last line here, seemingly rdx and rcx were both null according to the exception record (Possibly a failure of thread local storage??):
0:000> uf OurDll!MitigationPolicyChecker::getInstance
OurDll!MitigationPolicyChecker::getInstance:
8 000007fe`fbc38ed0 4883ec28 sub rsp,28h
9 000007fe`fbc38ed4 b804000000 mov eax,4
9 000007fe`fbc38ed9 8bc0 mov eax,eax
9 000007fe`fbc38edb 8b0dcf850b00 mov ecx,dword ptr [OurDll!_tls_index (000007fe`fbcf14b0)]
9 000007fe`fbc38ee1 65488b142558000000 mov rdx,qword ptr gs:[58h]
9 000007fe`fbc38eea 488b0cca mov rcx,qword ptr [rdx+rcx*8]
So what's going on here? The process has just one thread active at the time of the crash so I don't believe this is a concurrency issue. As far as I'm aware:
- The static object should be created on first access.
- Statics would ordinarily be initialized just prior to DllMain but in this case since it's a function level static it'll be created when its called and since it's VS2015 it'll be created as a "magic static".
Is there something I'm missing that makes this unsafe?