From f712e904ec6bfbee29111ac0104a777188ad61a1 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 4 Nov 2015 18:21:45 -0800 Subject: [PATCH 1/2] Restrict allocation of executable memory by DebuggerHeap DebuggerHeap is a common class that is used for both executable and non-executable memory allocations by debugging infrustructure. On Windows, OS supports concept of executable heap and CLR doesn't need to do anything extra for each executable allocation. On Linux/OSX this is not true. That's why this changes preserves fExecutable flag for each heap and makes sure that we mark memory as executable only when it is necessary. --- src/debug/ee/debugger.cpp | 21 +++++++++++++-------- src/debug/ee/debugger.h | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp index 26ae1b58fcb9..26621187819a 100644 --- a/src/debug/ee/debugger.cpp +++ b/src/debug/ee/debugger.cpp @@ -16566,6 +16566,7 @@ DebuggerHeap::DebuggerHeap() #ifdef USE_INTEROPSAFE_HEAP m_hHeap = NULL; #endif + m_fExecutable = FALSE; } @@ -16615,6 +16616,7 @@ HRESULT DebuggerHeap::Init(BOOL fExecutable) // Have knob catch if we don't want to lazy init the debugger. _ASSERTE(!g_DbgShouldntUseDebugger); + m_fExecutable = fExecutable; #ifdef USE_INTEROPSAFE_HEAP // If already inited, then we're done. @@ -16742,14 +16744,17 @@ void *DebuggerHeap::Alloc(DWORD size) #endif #ifdef FEATURE_PAL - // We don't have executable heap in PAL, but we still need to allocate - // executable memory, that's why have change protection level for - // each allocation. - // UNIXTODO: We need to look how JIT solves this problem. - DWORD unusedFlags; - if (!VirtualProtect(ret, size, PAGE_EXECUTE_READWRITE, &unusedFlags)) - { - _ASSERTE(!"VirtualProtect failed to make this memory executable"); + if (m_fExecutable) + { + // We don't have executable heap in PAL, but we still need to allocate + // executable memory, that's why have change protection level for + // each allocation. + // UNIXTODO: We need to look how JIT solves this problem. + DWORD unusedFlags; + if (!VirtualProtect(ret, size, PAGE_EXECUTE_READWRITE, &unusedFlags)) + { + _ASSERTE(!"VirtualProtect failed to make this memory executable"); + } } #endif // FEATURE_PAL diff --git a/src/debug/ee/debugger.h b/src/debug/ee/debugger.h index 2a1ca0cf10a0..9d25140cc025 100644 --- a/src/debug/ee/debugger.h +++ b/src/debug/ee/debugger.h @@ -1103,6 +1103,7 @@ class DebuggerHeap #ifdef USE_INTEROPSAFE_HEAP HANDLE m_hHeap; #endif + BOOL m_fExecutable; }; class DebuggerJitInfo; From 3e0b7deb1177e9196a9d47d6a564f7bf6c67e3fa Mon Sep 17 00:00:00 2001 From: Eugene Date: Thu, 5 Nov 2015 14:42:54 -0800 Subject: [PATCH 2/2] Selective VirtualProtect in debugger heap for Realloc --- src/debug/ee/debugger.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp index 26621187819a..613a64e8472a 100644 --- a/src/debug/ee/debugger.cpp +++ b/src/debug/ee/debugger.cpp @@ -16802,14 +16802,17 @@ void *DebuggerHeap::Realloc(void *pMem, DWORD newSize, DWORD oldSize) #ifdef FEATURE_PAL - // We don't have executable heap in PAL, but we still need to allocate - // executable memory, that's why have change protection level for - // each allocation. - // UNIXTODO: We need to look how JIT solves this problem. - DWORD unusedFlags; - if (!VirtualProtect(ret, newSize, PAGE_EXECUTE_READWRITE, &unusedFlags)) - { - _ASSERTE(!"VirtualProtect failed to make this memory executable"); + if (m_fExecutable) + { + // We don't have executable heap in PAL, but we still need to allocate + // executable memory, that's why have change protection level for + // each allocation. + // UNIXTODO: We need to look how JIT solves this problem. + DWORD unusedFlags; + if (!VirtualProtect(ret, newSize, PAGE_EXECUTE_READWRITE, &unusedFlags)) + { + _ASSERTE(!"VirtualProtect failed to make this memory executable"); + } } #endif // FEATURE_PAL