Bläddra i källkod

CFG support for ChakraCore

Enabled CFG in ChakraCore in a way which keeps the binary running on pre-Win10 (pre-CFG) OSs.
To make this safe, the necessary APIs are delayloaded at initialization time, and the function pointers and then put in a read-only data section.

Note: For CFG to be enabled, the host needs to be marked as supporting Win10 by linking with /subsystem, os as supporting multiple OS version through a manifest (see https://docs.microsoft.com/en-us/windows/desktop/SysInfo/targeting-your-application-at-windows-8-1).
Louis Lafreniere 7 år sedan
förälder
incheckning
76a06a261c

+ 2 - 0
Build/Common.Build.props

@@ -65,6 +65,8 @@
       <!-- /Gy -->
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <!-- /GF -->
+      <ControlFlowGuard Condition="'$(Platform)'!='ARM'">Guard</ControlFlowGuard>
+      <!-- /guard:cf -->
       <StringPooling>true</StringPooling>
       <!-- /MD -->
       <RuntimeLibrary Condition="'$(RuntimeLib)'!='static_library'">MultiThreadedDLL</RuntimeLibrary>

+ 21 - 0
bin/ch/ch.manifest

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+    <assemblyIdentity 
+        name="Microsoft.Chakra.ch.exe" 
+        version="1.0.0.0" 
+        type="win32" />
+    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
+        <application> 
+            <!-- Windows 10 --> 
+            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+            <!-- Windows 8.1 -->
+            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+            <!-- Windows 8 -->
+            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+            <!-- Windows 7 -->
+            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>      
+            <!-- Windows Vista -->
+            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>          
+        </application> 
+    </compatibility>
+</assembly>

+ 4 - 1
bin/ch/ch.vcxproj

@@ -123,6 +123,9 @@
       <Authenticode>Microsoft400</Authenticode>
     </FilesToSign>
   </ItemGroup>
+  <ItemGroup>
+    <Manifest Include="ch.manifest" />
+  </ItemGroup>
   <Import Project="$(BuildConfigPropsPath)Chakra.Build.targets" Condition="exists('$(BuildConfigPropsPath)Chakra.Build.targets')" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-</Project>
+</Project>

+ 1 - 1
lib/Backend/GlobOpt.cpp

@@ -5285,7 +5285,7 @@ GlobOpt::ValueNumberLdElemDst(IR::Instr **pInstr, Value *srcVal)
             }
         }
     }
-
+    
     IR::IndirOpnd *src = instr->GetSrc1()->AsIndirOpnd();
     const ValueType baseValueType(src->GetBaseOpnd()->GetValueType());
     if (instr->DoStackArgsOpt(this->func) ||

+ 7 - 1
lib/Common/CommonDefines.h

@@ -12,6 +12,10 @@
 #include "Warnings.h"
 #include "ChakraCoreVersion.h"
 
+// CFG was never enabled for ARM32 and requires WIN10 SDK
+#if !defined(_M_ARM) && defined(_WIN32) && defined(NTDDI_WIN10)
+#define _CONTROL_FLOW_GUARD 1
+#endif
 
 //----------------------------------------------------------------------------------------------------
 // Default debug/fretest/release flags values
@@ -316,7 +320,9 @@
 #endif
 
 // Other features
-// #define CHAKRA_CORE_DOWN_COMPAT 1
+#if defined(_CHAKRACOREBUILD)
+# define CHAKRA_CORE_DOWN_COMPAT 1
+#endif
 
 // todo:: Enable vectorcall on NTBUILD. OS#13609380
 #if defined(_WIN32) && !defined(NTBUILD) && defined(_M_IX86)

+ 1 - 0
lib/Common/Core/CMakeLists.txt

@@ -11,6 +11,7 @@ add_library (Chakra.Common.Core OBJECT
     DelayLoadLibrary.cpp
     EtwTraceCore.cpp
     FaultInjection.cpp
+    GlobalSecurityPolicy.cpp
     Output.cpp
     PerfCounter.cpp
     PerfCounterImpl.cpp

+ 117 - 8
lib/Common/Core/GlobalSecurityPolicy.cpp

@@ -5,32 +5,126 @@
 
 #include "CommonCorePch.h"
 
-#pragma section(".mrdata", read)
+#ifdef _WIN32
+
+#include <VersionHelpers.h>
+
 
 CriticalSection GlobalSecurityPolicy::s_policyCS;
+GlobalSecurityPolicy GlobalSecurityObject;
+
+#pragma section(".mrdata", read)
+
+// Note:  'volatile' is necessary here otherwise the compiler assumes these are constants initialized to '0' and will constant propagate them...
+__declspec(allocate(".mrdata")) volatile GlobalSecurityPolicy::ReadOnlyData GlobalSecurityPolicy::readOnlyData =
+    {
+#if defined(_CONTROL_FLOW_GUARD)
+        nullptr,
+        nullptr,
+#endif
+        false,
+        false,
+        false
+    };
+
+bool
+GlobalSecurityPolicy::IsCFGEnabled()
+{
+    return readOnlyData.isCFGEnabled && !PHASE_OFF1(Js::CFGPhase);
+}
+
+bool 
+GlobalSecurityPolicy::InitIsCFGEnabled()
+{
+#if defined(_CONTROL_FLOW_GUARD)
+    PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY CfgPolicy;
+    BOOL isGetMitigationPolicySucceeded = GlobalSecurityPolicy::GetMitigationPolicyForProcess(
+        GetCurrentProcess(),
+        ProcessControlFlowGuardPolicy,
+        &CfgPolicy,
+        sizeof(CfgPolicy));
+    AssertOrFailFast(isGetMitigationPolicySucceeded);
+    return CfgPolicy.EnableControlFlowGuard;
+
+#else
+    return false;
+#endif // _CONTROL_FLOW_GUARD
+}
+
+GlobalSecurityPolicy::GlobalSecurityPolicy()
+{
+#if defined(_CONTROL_FLOW_GUARD)
+    AutoCriticalSection autocs(&s_policyCS);
+    DWORD oldProtect;
+
+    // Make sure this is called only once
+    AssertOrFailFast(!readOnlyData.isInitialized);
+
+#if defined(CHAKRA_CORE_DOWN_COMPAT)
+    if (AutoSystemInfo::Data.IsWinThresholdOrLater())
+#endif
+    {
+        // Make readOnlyData read-write
+        BOOL res = VirtualProtect((LPVOID)&readOnlyData, sizeof(ReadOnlyData), PAGE_READWRITE, &oldProtect);
+        if ((res == FALSE) || (oldProtect != PAGE_READONLY))
+        {
+            RaiseFailFastException(nullptr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
+        }
+
+        readOnlyData.isInitialized = true;
+
+        EnsureFromSystemDirOnly();
+
+        if (m_hModule)
+        {
+            readOnlyData.pfnGetProcessMitigationPolicy = (PFNCGetMitigationPolicyForProcess)GetFunction("GetProcessMitigationPolicy");
+            if (readOnlyData.pfnGetProcessMitigationPolicy == nullptr)
+            {
+                RaiseFailFastException(nullptr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
+            }
+
+            readOnlyData.isCFGEnabled = InitIsCFGEnabled();
+
+            if (readOnlyData.isCFGEnabled)
+            {
+                readOnlyData.pfnSetProcessValidCallTargets = (PFNCSetProcessValidCallTargets)GetFunction("SetProcessValidCallTargets");
+                if (readOnlyData.pfnSetProcessValidCallTargets == nullptr)
+                {
+                    RaiseFailFastException(nullptr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
+                }
+            }
+        }
+
+        // Make readOnlyData read-only again.
+        res = VirtualProtect((LPVOID)&readOnlyData, sizeof(ReadOnlyData), PAGE_READONLY, &oldProtect);
+        if ((res == FALSE) || (oldProtect != PAGE_READWRITE))
+        {
+            RaiseFailFastException(nullptr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
+        }
+    }
 
-__declspec(allocate(".mrdata"))
-volatile bool GlobalSecurityPolicy::s_ro_disableSetProcessValidCallTargets = false;
+#endif //_CONTROL_FLOW_GUARD
+    }
 
 void
 GlobalSecurityPolicy::DisableSetProcessValidCallTargets()
 {
     // One-way transition from allowing SetProcessValidCallTargets to disabling
     // the API.
-    if (!s_ro_disableSetProcessValidCallTargets)
+    if (!readOnlyData.disableSetProcessValidCallTargets)
     {
         AutoCriticalSection autocs(&s_policyCS);
         DWORD oldProtect;
 
-        BOOL res = VirtualProtect((LPVOID)&s_ro_disableSetProcessValidCallTargets, sizeof(s_ro_disableSetProcessValidCallTargets), PAGE_READWRITE, &oldProtect);
+        BOOL res = VirtualProtect((LPVOID)&readOnlyData, sizeof(ReadOnlyData), PAGE_READWRITE, &oldProtect);
         if ((res == FALSE) || (oldProtect != PAGE_READONLY))
         {
             RaiseFailFastException(nullptr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
         }
     
-        s_ro_disableSetProcessValidCallTargets = true;
+        readOnlyData.disableSetProcessValidCallTargets = true;
     
-        res = VirtualProtect((LPVOID)&s_ro_disableSetProcessValidCallTargets, sizeof(s_ro_disableSetProcessValidCallTargets), PAGE_READONLY, &oldProtect);
+        res = VirtualProtect((LPVOID)&readOnlyData, sizeof(ReadOnlyData), PAGE_READONLY, &oldProtect);
         if ((res == FALSE) || (oldProtect != PAGE_READWRITE))
         {
             RaiseFailFastException(nullptr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
@@ -41,5 +135,20 @@ GlobalSecurityPolicy::DisableSetProcessValidCallTargets()
 bool
 GlobalSecurityPolicy::IsSetProcessValidCallTargetsAllowed()
 {
-    return !s_ro_disableSetProcessValidCallTargets;
+    return !readOnlyData.disableSetProcessValidCallTargets;
+}
+
+#if defined(_CONTROL_FLOW_GUARD)
+BOOL 
+DECLSPEC_GUARDNOCF GlobalSecurityPolicy::GetMitigationPolicyForProcess(HANDLE hProcess, PROCESS_MITIGATION_POLICY mitigationPolicy, PVOID lpBuffer, SIZE_T dwLength)
+{
+    return GlobalSecurityPolicy::readOnlyData.pfnGetProcessMitigationPolicy(hProcess, mitigationPolicy, lpBuffer, dwLength);
+}
+
+BOOL
+DECLSPEC_GUARDNOCF GlobalSecurityPolicy::SetProcessValidCallTargets(HANDLE hProcess, PVOID virtualAddress, SIZE_T regionSize, ULONG numberOfOffsets, PCFG_CALL_TARGET_INFO offsetInformation)
+{
+    return GlobalSecurityPolicy::readOnlyData.pfnSetProcessValidCallTargets(hProcess, virtualAddress, regionSize, numberOfOffsets, offsetInformation);
 }
+#endif //_CONTROL_FLOW_GUARD
+#endif // _WIN32

+ 34 - 2
lib/Common/Core/GlobalSecurityPolicy.h

@@ -4,14 +4,46 @@
 //-------------------------------------------------------------------------------------------------------
 #pragma once
 
-class GlobalSecurityPolicy
+#include "DelayLoadLibrary.h"
+
+class GlobalSecurityPolicy : private DelayLoadLibrary
 {
 public:
+#ifdef _WIN32
+#if defined(_CONTROL_FLOW_GUARD)
+    typedef BOOL FNCGetMitigationPolicyForProcess(HANDLE, PROCESS_MITIGATION_POLICY, PVOID, SIZE_T);
+    typedef FNCGetMitigationPolicyForProcess* PFNCGetMitigationPolicyForProcess;
+
+    typedef BOOL FNCSetProcessValidCallTargets(HANDLE, PVOID, SIZE_T, ULONG, PCFG_CALL_TARGET_INFO);
+    typedef FNCSetProcessValidCallTargets* PFNCSetProcessValidCallTargets;
+#endif
+    GlobalSecurityPolicy();
+
     static void DisableSetProcessValidCallTargets();
     static bool IsSetProcessValidCallTargetsAllowed();
+    static bool IsCFGEnabled();
+
+#if defined(_CONTROL_FLOW_GUARD)
+    static FNCGetMitigationPolicyForProcess GetMitigationPolicyForProcess;
+    static FNCSetProcessValidCallTargets SetProcessValidCallTargets;
+#endif
+    LPCTSTR GetLibraryName() const { return _u("api-ms-win-core-memory-l1-1-3.dll"); }
 
 private:
     static CriticalSection s_policyCS;
 
-    static volatile bool s_ro_disableSetProcessValidCallTargets;
+    volatile static struct ReadOnlyData {
+#if defined(_CONTROL_FLOW_GUARD)
+        PFNCGetMitigationPolicyForProcess pfnGetProcessMitigationPolicy;
+        PFNCSetProcessValidCallTargets pfnSetProcessValidCallTargets;
+#endif
+        bool disableSetProcessValidCallTargets;
+        bool isCFGEnabled;
+        bool isInitialized;
+    } readOnlyData;
+
+    static bool InitIsCFGEnabled();
+#else
+    static bool IsCFGEnabled() { return false; }
+#endif
 };

+ 0 - 14
lib/Common/Core/SysInfo.cpp

@@ -360,20 +360,6 @@ AutoSystemInfo::CheckForAtom() const
 }
 #endif
 
-bool
-AutoSystemInfo::IsCFGEnabled()
-{
-#if defined(_CONTROL_FLOW_GUARD)
-    return true
-#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
-        && IsWinThresholdOrLater() && !PHASE_OFF1(Js::CFGPhase)
-#endif //ENABLE_DEBUG_CONFIG_OPTIONS
-        ;
-#else
-    return false;
-#endif //_CONTROL_FLOW_GUARD
-}
-
 bool
 AutoSystemInfo::IsWin8OrLater()
 {

+ 0 - 1
lib/Common/Core/SysInfo.h

@@ -15,7 +15,6 @@ public:
     uint GetAllocationGranularityPageSize() const;
 
     bool DisableDebugScopeCapture() const { return this->disableDebugScopeCapture; }
-    bool IsCFGEnabled();
     bool IsWin8OrLater();
 #if defined(_CONTROL_FLOW_GUARD)
     bool IsWinThresholdOrLater();

+ 6 - 6
lib/Common/Memory/CustomHeap.cpp

@@ -288,7 +288,7 @@ BOOL Heap<TAlloc, TPreReservedAlloc>::ProtectAllocationWithExecuteReadWrite(Allo
 {
     DWORD protectFlags = 0;
 
-    if (AutoSystemInfo::Data.IsCFGEnabled())
+    if (GlobalSecurityPolicy::IsCFGEnabled())
     {
         protectFlags = PAGE_EXECUTE_RW_TARGETS_NO_UPDATE;
     }
@@ -303,7 +303,7 @@ template<typename TAlloc, typename TPreReservedAlloc>
 BOOL Heap<TAlloc, TPreReservedAlloc>::ProtectAllocationWithExecuteReadOnly(__in Allocation *allocation, __in_opt char* addressInPage)
 {
     DWORD protectFlags = 0;
-    if (AutoSystemInfo::Data.IsCFGEnabled())
+    if (GlobalSecurityPolicy::IsCFGEnabled())
     {
         protectFlags = PAGE_EXECUTE_RO_TARGETS_NO_UPDATE;
     }
@@ -417,7 +417,7 @@ Allocation* Heap<TAlloc, TPreReservedAlloc>::AllocLargeObject(size_t bytes, usho
         if (this->processHandle == GetCurrentProcess())
         {
             DWORD protectFlags = 0;
-            if (AutoSystemInfo::Data.IsCFGEnabled())
+            if (GlobalSecurityPolicy::IsCFGEnabled())
             {
                 protectFlags = PAGE_EXECUTE_RO_TARGETS_NO_UPDATE;
             }
@@ -513,7 +513,7 @@ DWORD Heap<TAlloc, TPreReservedAlloc>::EnsureAllocationWriteable(Allocation* all
 template<typename TAlloc, typename TPreReservedAlloc>
 DWORD Heap<TAlloc, TPreReservedAlloc>::EnsureAllocationExecuteWriteable(Allocation* allocation)
 {
-    if (AutoSystemInfo::Data.IsCFGEnabled())
+    if (GlobalSecurityPolicy::IsCFGEnabled())
     {
         return EnsureAllocationReadWrite<PAGE_EXECUTE_RW_TARGETS_NO_UPDATE>(allocation);
     }
@@ -685,7 +685,7 @@ Page* Heap<TAlloc, TPreReservedAlloc>::AllocNewPage(BucketId bucket, bool canAll
 
     DWORD protectFlags = 0;
 
-    if (AutoSystemInfo::Data.IsCFGEnabled())
+    if (GlobalSecurityPolicy::IsCFGEnabled())
     {
         protectFlags = PAGE_EXECUTE_RO_TARGETS_NO_UPDATE;
     }
@@ -885,7 +885,7 @@ bool Heap<TAlloc, TPreReservedAlloc>::FreeAllocation(Allocation* object)
 
         DWORD protectFlags = 0;
 
-        if (AutoSystemInfo::Data.IsCFGEnabled())
+        if (GlobalSecurityPolicy::IsCFGEnabled())
         {
             protectFlags = PAGE_EXECUTE_RO_TARGETS_NO_UPDATE;
         }

+ 1 - 1
lib/Common/Memory/PageAllocator.cpp

@@ -2665,7 +2665,7 @@ HeapPageAllocator<T>::ProtectPages(__in char* address, size_t pageCount, __in vo
 
     /*Verify if we always pass the PAGE_TARGETS_NO_UPDATE flag, if the protect flag is EXECUTE*/
 #if defined(_CONTROL_FLOW_GUARD)
-    if (AutoSystemInfo::Data.IsCFGEnabled() &&
+    if (GlobalSecurityPolicy::IsCFGEnabled() &&
         (dwVirtualProtectFlags & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) &&
         ((dwVirtualProtectFlags & PAGE_TARGETS_NO_UPDATE) == 0))
     {

+ 2 - 2
lib/Common/Memory/SectionAllocWrapper.cpp

@@ -99,7 +99,7 @@ PVOID MapView(HANDLE process, HANDLE sectionHandle, size_t size, size_t offset,
         {
             return nullptr;
         }
-        flags = AutoSystemInfo::Data.IsCFGEnabled() ? PAGE_EXECUTE_RO_TARGETS_INVALID : PAGE_EXECUTE_READ;
+        flags = GlobalSecurityPolicy::IsCFGEnabled() ? PAGE_EXECUTE_RO_TARGETS_INVALID : PAGE_EXECUTE_READ;
     }
 
 #if USEFILEMAP2
@@ -860,7 +860,7 @@ LPVOID PreReservedSectionAllocWrapper::EnsurePreReservedRegionInternal()
 #endif // _M_IX86
 #endif
 
-    if (AutoSystemInfo::Data.IsCFGEnabled() && supportPreReservedRegion)
+    if (GlobalSecurityPolicy::IsCFGEnabled() && supportPreReservedRegion)
     {
         HANDLE sectionHandle = CreateSection(bytes, false);
         if (sectionHandle == nullptr)

+ 5 - 12
lib/Common/Memory/VirtualAllocWrapper.cpp

@@ -38,12 +38,12 @@ LPVOID VirtualAllocWrapper::AllocPages(LPVOID lpAddress, size_t pageCount, DWORD
 
 #if defined(_CONTROL_FLOW_GUARD)
     DWORD oldProtectFlags = 0;
-    if (AutoSystemInfo::Data.IsCFGEnabled() && isCustomHeapAllocation)
+    if (GlobalSecurityPolicy::IsCFGEnabled() && isCustomHeapAllocation)
     {
         //We do the allocation in two steps - CFG Bitmap in kernel will be created only on allocation with EXECUTE flag.
         //We again call VirtualProtect to set to the requested protectFlags.
         DWORD allocProtectFlags = 0;
-        if (AutoSystemInfo::Data.IsCFGEnabled())
+        if (GlobalSecurityPolicy::IsCFGEnabled())
         {
             allocProtectFlags = PAGE_EXECUTE_RW_TARGETS_INVALID;
         }
@@ -245,7 +245,7 @@ LPVOID PreReservedVirtualAllocWrapper::EnsurePreReservedRegionInternal()
 #endif // _M_IX86
 #endif
 
-    if (AutoSystemInfo::Data.IsCFGEnabled() && supportPreReservedRegion)
+    if (GlobalSecurityPolicy::IsCFGEnabled() && supportPreReservedRegion)
     {
         startAddress = VirtualAlloc(NULL, bytes, MEM_RESERVE, PAGE_READWRITE);
         PreReservedHeapTrace(_u("Reserving PreReservedSegment For the first time(CFG Enabled). Address: 0x%p\n"), preReservedStartAddress);
@@ -359,19 +359,12 @@ LPVOID PreReservedVirtualAllocWrapper::AllocPages(LPVOID lpAddress, size_t pageC
 #endif
 
 #if defined(_CONTROL_FLOW_GUARD)
-            if (AutoSystemInfo::Data.IsCFGEnabled())
+            if (GlobalSecurityPolicy::IsCFGEnabled())
             {
                 DWORD oldProtect = 0;
                 DWORD allocProtectFlags = 0;
 
-                if (AutoSystemInfo::Data.IsCFGEnabled())
-                {
-                    allocProtectFlags = PAGE_EXECUTE_RW_TARGETS_INVALID;
-                }
-                else
-                {
-                    allocProtectFlags = PAGE_EXECUTE_READWRITE;
-                }
+                allocProtectFlags = PAGE_EXECUTE_RW_TARGETS_INVALID;
 
                 allocatedAddress = (char *)VirtualAlloc(addressToReserve, dwSize, MEM_COMMIT, allocProtectFlags);
                 if (allocatedAddress != nullptr)

+ 2 - 115
lib/Runtime/Base/DelayLoadLibrary.cpp

@@ -393,132 +393,19 @@ namespace Js
     }
 #endif
 
-#ifdef _CONTROL_FLOW_GUARD
-// Note. __declspec(guard(nocf)) causes the CFG check to be removed
-// inside this function, and is needed only for test binaries (chk and FRETEST)
-#if defined(DELAYLOAD_SET_CFG_TARGET)
-    DECLSPEC_GUARDNOCF
-#endif
-    BOOL DelayLoadWinCoreMemory::SetProcessCallTargets(_In_ HANDLE hProcess,
-        _In_ PVOID VirtualAddress,
-        _In_ SIZE_T RegionSize,
-        _In_ ULONG NumberOfOffsets,
-        _In_reads_(NumberOfOffsets) PCFG_CALL_TARGET_INFO OffsetInformation)
-    {
-#if defined(ENABLE_JIT_CLAMP)
-        // Ensure that dynamic code generation is allowed for this thread as
-        // this is required for the call to SetProcessValidCallTargets to
-        // succeed.
-        AutoEnableDynamicCodeGen enableCodeGen;
-#endif
-
-#if defined(DELAYLOAD_SET_CFG_TARGET)
-        if (m_hModule)
-        {
-            if (m_pfnSetProcessValidCallTargets == nullptr)
-            {
-                m_pfnSetProcessValidCallTargets = (PFNCSetProcessValidCallTargets) GetFunction("SetProcessValidCallTargets");
-                if (m_pfnSetProcessValidCallTargets == nullptr)
-                {
-                    return FALSE;
-                }
-            }
-
-            Assert(m_pfnSetProcessValidCallTargets != nullptr);
-            return m_pfnSetProcessValidCallTargets(hProcess, VirtualAddress, RegionSize, NumberOfOffsets, OffsetInformation);
-        }
-
-        return FALSE;
-#else
-        return SetProcessValidCallTargets(hProcess, VirtualAddress, RegionSize, NumberOfOffsets, OffsetInformation);
-#endif
-    }
-
-    // Note. __declspec(guard(nocf)) causes the CFG check to be removed
-    // inside this function, and is needed only for test binaries (chk and FRETEST)
-#if defined(DELAYLOAD_SET_CFG_TARGET)
-    DECLSPEC_GUARDNOCF
-#endif
-        BOOL DelayLoadWinCoreMemory::SetProcessCallTargetsForMappedView(
-            _In_ HANDLE Process,
-            _In_ PVOID ViewBase,
-            _In_ SIZE_T ViewSize,
-            _In_ ULONG NumberOfOffsets,
-            _Inout_updates_(NumberOfOffsets) PCFG_CALL_TARGET_INFO OffsetInformation,
-            _In_ HANDLE Section,
-            _In_ ULONG64 FileOffset)
-    {
-#if defined(ENABLE_JIT_CLAMP)
-        // Ensure that dynamic code generation is allowed for this thread as
-        // this is required for the call to SetProcessValidCallTargets to
-        // succeed.
-        AutoEnableDynamicCodeGen enableCodeGen;
-#endif
-
-#if defined(DELAYLOAD_SET_CFG_TARGET)
-        if (m_hModule)
-        {
-            if (m_pfnSetProcessValidCallTargetsForMappedView == nullptr)
-            {
-                m_pfnSetProcessValidCallTargetsForMappedView = (PFNCSetProcessValidCallTargetsForMappedView)GetFunction("SetProcessValidCallTargetsForMappedView");
-                if (m_pfnSetProcessValidCallTargetsForMappedView == nullptr)
-                {
-                    return FALSE;
-                }
-            }
-
-            Assert(m_pfnSetProcessValidCallTargetsForMappedView != nullptr);
-            return m_pfnSetProcessValidCallTargetsForMappedView(Process, ViewBase, ViewSize, NumberOfOffsets, OffsetInformation, Section, FileOffset);
-        }
-
-        return FALSE;
-#else
-        return SetProcessValidCallTargetsForMappedView(Process, ViewBase, ViewSize, NumberOfOffsets, OffsetInformation, Section, FileOffset);
-#endif
-    }
-#endif
-
-    BOOL DelayLoadWinCoreProcessThreads::GetMitigationPolicyForProcess(
-        __in HANDLE hProcess,
-        __in PROCESS_MITIGATION_POLICY MitigationPolicy,
-        __out_bcount(nLength) PVOID lpBuffer,
-        __in SIZE_T nLength
-        )
-    {
-#if defined(DELAYLOAD_SET_CFG_TARGET)
-        if (m_hModule)
-        {
-            if (m_pfnGetProcessMitigationPolicy == nullptr)
-            {
-                m_pfnGetProcessMitigationPolicy = (PFNCGetMitigationPolicyForProcess) GetFunction("GetProcessMitigationPolicy");
-                if (m_pfnGetProcessMitigationPolicy == nullptr)
-                {
-                    return FALSE;
-                }
-            }
-
-            Assert(m_pfnGetProcessMitigationPolicy != nullptr);
-            return m_pfnGetProcessMitigationPolicy(hProcess, MitigationPolicy, lpBuffer, nLength);
-        }
-        return FALSE;
-#else
-        return BinaryFeatureControl::GetMitigationPolicyForProcess(hProcess, MitigationPolicy, lpBuffer, nLength);
-#endif // ENABLE_DEBUG_CONFIG_OPTIONS
-    }
-
     BOOL DelayLoadWinCoreProcessThreads::GetProcessInformation(
         __in HANDLE hProcess,
         __in PROCESS_INFORMATION_CLASS ProcessInformationClass,
         __out_bcount(nLength) PVOID lpBuffer,
         __in SIZE_T nLength
-        )
+    )
     {
 #if defined(DELAYLOAD_SET_CFG_TARGET) || defined(_M_ARM)
         if (m_hModule)
         {
             if (m_pfnGetProcessInformation == nullptr)
             {
-                m_pfnGetProcessInformation = (PFNCGetProcessInformation) GetFunction("GetProcessInformation");
+                m_pfnGetProcessInformation = (PFNCGetProcessInformation)GetFunction("GetProcessInformation");
                 if (m_pfnGetProcessInformation == nullptr)
                 {
                     return FALSE;

+ 3 - 51
lib/Runtime/Base/DelayLoadLibrary.h

@@ -225,50 +225,10 @@ namespace Js
     };
 #endif
 
-#if defined(_CONTROL_FLOW_GUARD)
-    class DelayLoadWinCoreMemory sealed : public DelayLoadLibrary
-    {
-    private:
-        // LoadWinCoreMemory specific functions
-        typedef BOOL FNCSetProcessValidCallTargets(HANDLE, PVOID, SIZE_T, ULONG, PCFG_CALL_TARGET_INFO);
-        typedef FNCSetProcessValidCallTargets* PFNCSetProcessValidCallTargets;
-        PFNCSetProcessValidCallTargets m_pfnSetProcessValidCallTargets;
-
-        typedef BOOL(*PFNCSetProcessValidCallTargetsForMappedView)(HANDLE, PVOID, SIZE_T, ULONG, PCFG_CALL_TARGET_INFO, HANDLE, ULONG64);
-        PFNCSetProcessValidCallTargetsForMappedView m_pfnSetProcessValidCallTargetsForMappedView;
-    public:
-        DelayLoadWinCoreMemory() : DelayLoadLibrary(),
-            m_pfnSetProcessValidCallTargets(nullptr), m_pfnSetProcessValidCallTargetsForMappedView(nullptr) { }
-
-        LPCTSTR GetLibraryName() const { return _u("api-ms-win-core-memory-l1-1-3.dll"); }
-
-        BOOL SetProcessCallTargets(
-            _In_ HANDLE hProcess,
-            _In_ PVOID VirtualAddress,
-            _In_ SIZE_T RegionSize,
-            _In_ ULONG NumberOfOffsets,
-            _In_reads_(NumberOfOffsets) PCFG_CALL_TARGET_INFO OffsetInformation
-            );
-
-        BOOL SetProcessCallTargetsForMappedView(
-            _In_ HANDLE Process,
-            _In_ PVOID ViewBase,
-            _In_ SIZE_T ViewSize,
-            _In_ ULONG NumberOfOffsets,
-            _Inout_updates_(NumberOfOffsets) PCFG_CALL_TARGET_INFO OffsetInformation,
-            _In_ HANDLE Section,
-            _In_ ULONG64 FileOffset
-        );
-    };
-#endif
-
     class DelayLoadWinCoreProcessThreads sealed : public DelayLoadLibrary
     {
     private:
         // LoadWinCoreMemory specific functions
-        typedef BOOL FNCGetMitigationPolicyForProcess(HANDLE, PROCESS_MITIGATION_POLICY, PVOID, SIZE_T);
-        typedef FNCGetMitigationPolicyForProcess* PFNCGetMitigationPolicyForProcess;
-        PFNCGetMitigationPolicyForProcess m_pfnGetProcessMitigationPolicy;
 
         typedef BOOL FNCGetProcessInformation(HANDLE, PROCESS_INFORMATION_CLASS, PVOID, SIZE_T);
         typedef FNCGetProcessInformation* PFNCGetProcessInformation;
@@ -277,26 +237,18 @@ namespace Js
     public:
         DelayLoadWinCoreProcessThreads() :
             DelayLoadLibrary(),
-            m_pfnGetProcessMitigationPolicy(nullptr),
             m_pfnGetProcessInformation(nullptr)
-            {
-            }
+        {
+        }
 
         LPCTSTR GetLibraryName() const { return _u("api-ms-win-core-processthreads-l1-1-3.dll"); }
 
-        BOOL GetMitigationPolicyForProcess(
-            __in HANDLE hProcess,
-            __in PROCESS_MITIGATION_POLICY MitigationPolicy,
-            __out_bcount(nLength) PVOID lpBuffer,
-            __in SIZE_T nLength
-            );
-
         BOOL GetProcessInformation(
             __in HANDLE hProcess,
             __in PROCESS_INFORMATION_CLASS ProcessInformationClass,
             __out_bcount(nLength) PVOID lpBuffer,
             __in SIZE_T nLength
-            );
+        );
     };
 
 #ifdef ENABLE_PROJECTION

+ 6 - 0
lib/Runtime/Base/ScriptContext.cpp

@@ -41,6 +41,12 @@
 #include "Language/SimpleDataCacheWrapper.h"
 #include "Core/CRC.h"
 
+#ifdef _M_IX86
+#ifdef _CONTROL_FLOW_GUARD
+extern "C" PVOID __guard_check_icall_fptr;
+#endif
+#endif
+
 namespace Js
 {
     ScriptContext * ScriptContext::New(ThreadContext * threadContext)

+ 15 - 33
lib/Runtime/Base/ThreadContextInfo.cpp

@@ -16,7 +16,11 @@
 #endif
 
 #if defined(_UCRT) && _CONTROL_FLOW_GUARD
-#include <cfguard.h>
+# if _MSC_VER >= 1913
+#  include <cfguard.h>
+# else
+   extern "C" void __fastcall _guard_check_icall(_In_ uintptr_t _Target);
+# endif
 #endif
 
 ThreadContextInfo::ThreadContextInfo() :
@@ -375,42 +379,16 @@ ThreadContextInfo::ResetIsAllJITCodeInPreReservedRegion()
 }
 
 #ifdef ENABLE_GLOBALIZATION
-
-#if defined(_CONTROL_FLOW_GUARD)
+# if defined(_CONTROL_FLOW_GUARD)
 Js::DelayLoadWinCoreProcessThreads *
 ThreadContextInfo::GetWinCoreProcessThreads()
 {
     m_delayLoadWinCoreProcessThreads.EnsureFromSystemDirOnly();
     return &m_delayLoadWinCoreProcessThreads;
 }
-
-Js::DelayLoadWinCoreMemory *
-ThreadContextInfo::GetWinCoreMemoryLibrary()
-{
-    m_delayLoadWinCoreMemoryLibrary.EnsureFromSystemDirOnly();
-    return &m_delayLoadWinCoreMemoryLibrary;
-}
+# endif
 #endif
 
-bool
-ThreadContextInfo::IsCFGEnabled()
-{
-#if defined(_CONTROL_FLOW_GUARD)
-    PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY CfgPolicy;
-    m_delayLoadWinCoreProcessThreads.EnsureFromSystemDirOnly();
-    BOOL isGetMitigationPolicySucceeded = m_delayLoadWinCoreProcessThreads.GetMitigationPolicyForProcess(
-        GetCurrentProcess(),
-        ProcessControlFlowGuardPolicy,
-        &CfgPolicy,
-        sizeof(CfgPolicy));
-    Assert(isGetMitigationPolicySucceeded || !AutoSystemInfo::Data.IsCFGEnabled());
-    return CfgPolicy.EnableControlFlowGuard && AutoSystemInfo::Data.IsCFGEnabled();
-#else
-    return false;
-#endif // _CONTROL_FLOW_GUARD
-}
-#endif // ENABLE_GLOBALIZATION
-
 //Masking bits according to AutoSystemInfo::PageSize
 #define PAGE_START_ADDR(address) ((size_t)(address) & ~(size_t)(AutoSystemInfo::PageSize - 1))
 #define IS_16BYTE_ALIGNED(address) (((size_t)(address) & 0xF) == 0)
@@ -427,7 +405,7 @@ ThreadContextInfo::SetValidCallTargetInternal(
     AnalysisAssert(!useFileAPI || fileHandle);
     AnalysisAssert(!useFileAPI || viewBase);
 #ifdef _CONTROL_FLOW_GUARD
-    if (IsCFGEnabled())
+    if (GlobalSecurityPolicy::IsCFGEnabled())
     {
 #ifdef _M_ARM
         AssertMsg(((uintptr_t)callTargetAddress & 0x1) != 0, "on ARM we expect the thumb bit to be set on anything we use as a call target");
@@ -487,7 +465,7 @@ ThreadContextInfo::SetValidCallTargetInternal(
             AssertMsg((size_t)callTargetAddress - (size_t)startAddressOfPage <= AutoSystemInfo::PageSize - 1, "Only last bits corresponding to PageSize should be masked");
             AssertMsg((size_t)startAddressOfPage + (size_t)codeOffset == (size_t)callTargetAddress, "Wrong masking of address?");
 
-            isCallTargetRegistrationSucceed = GetWinCoreMemoryLibrary()->SetProcessCallTargets(GetProcessHandle(), startAddressOfPage, AutoSystemInfo::PageSize, 1, callTargetInfo);
+            isCallTargetRegistrationSucceed = GlobalSecurityPolicy::SetProcessValidCallTargets(GetProcessHandle(), startAddressOfPage, AutoSystemInfo::PageSize, 1, callTargetInfo);
         }
         if (!isCallTargetRegistrationSucceed)
         {
@@ -509,9 +487,13 @@ ThreadContextInfo::SetValidCallTargetInternal(
             }
         }
 #if DBG
-        if (isSetValid && !JITManager::GetJITManager()->IsOOPJITEnabled())
+        if (isSetValid
+#if ENABLE_OOP_NATIVE_CODEGEN
+            && !JITManager::GetJITManager()->IsOOPJITEnabled()
+#endif
+            )
         {
-            _GUARD_CHECK_ICALL((uintptr_t)callTargetAddress);
+            _guard_check_icall((uintptr_t)callTargetAddress);
         }
 
         if (PHASE_TRACE1(Js::CFGPhase))

+ 0 - 4
lib/Runtime/Base/ThreadContextInfo.h

@@ -114,14 +114,10 @@ public:
 
     bool CanBeFalsy(Js::TypeId typeId) { return typeId == this->wellKnownHostTypeIds[WellKnownHostType_HTMLAllCollection]; }
 
-    bool IsCFGEnabled();
     bool IsClosed();
 
 #if defined(ENABLE_GLOBALIZATION) && defined(_CONTROL_FLOW_GUARD)
-    Js::DelayLoadWinCoreMemory * GetWinCoreMemoryLibrary();
     Js::DelayLoadWinCoreProcessThreads * GetWinCoreProcessThreads();
-
-    Js::DelayLoadWinCoreMemory m_delayLoadWinCoreMemoryLibrary;
     Js::DelayLoadWinCoreProcessThreads m_delayLoadWinCoreProcessThreads;
 #endif
 

+ 2 - 1
lib/Runtime/Library/JavascriptFunction.cpp

@@ -2949,7 +2949,7 @@ LABEL1:
     PropertyQueryFlags JavascriptFunction::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
     {
         BOOL result;
-        PropertyRecord const* propertyRecord;
+        PropertyRecord const* propertyRecord = nullptr;
         this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
 
         result = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext)) ? TRUE : FALSE;
@@ -2996,6 +2996,7 @@ LABEL1:
             }
         }
 
+        *result = false;
         return false;
     }