In my recent Black Hat USA talk on the attack surface and exploit mitigations in EdgeHTML (Microsoft Edge’s new rendering engine), one of the topics that I discussed was Memory GC (MemGC), a new and improved use-after-free (UAF) exploit mitigation introduced by Microsoft in Edge and IE on Windows 10.
MemGC was first introduced in Edge’s EdgeHTML rendering engine and in IE’s Trident (MSHTML) rendering engine on Windows 10. It is the successor to the Memory Protector UAF exploit mitigation in the aforementioned rendering engines on Windows 10.
Similar to Memory Protector, the purpose of MemGC is to mitigate exploitation of UAF vulnerabilities by preventing the freeing of memory chunks if references to them are found. However, unlike Memory Protector, which only checks the registers and the stack for chunk references, MemGC also scans the contents of MemGC-managed chunks for references. This additional check means that MemGC further decreases the number of usable UAF bugs that an attacker can exploit.
MemGC is enabled by default. One way to configure it in both Edge and IE is via the OverrideMemoryProtectionSetting configuration, which can be set via the following registry entry:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\Main::OverrideMemoryProtectionSetting = %DwordValue%
Where %DwordValue% can be any of the following:
- 3: MemGC is enabled (default).
- 2: Memory Protector is enabled (force mark-and-reclaim).
- 1: Memory Protector is enabled.
- 0: MemGC and Memory Protector are disabled.
The allocation scheme used involves committing chunks of memory called Segments using VirtualAlloc() and then dividing these Segments into 4096-byte Pages. A group of these Pages are then treated as a Block, which is in turn used in the allocation of similarly sized objects.
EdgeHTML/MSHTML DOM objects and many internal rendering engine objects are managed by MemGC. And because MemGC already uses a separate managed heap, the Isolated Heap is unused if MemGC is enabled.
In EdgeHTML’s implementation of MemGC, when a MemGC-managed object needs to be allocated, edgehtml!MemoryProtection::HeapAlloc<1>() or edgehtml!MemoryProtection::HeapAllocClear<1>() is called, which in turn calls chakra!MemProtectHeapRootAlloc().
Chakra!MemProtectHeapRootAlloc() will then allocate a chunk from a Block in the appropriate bucket and then flag the chunk as a root. In garbage collection parlance, root means that the object is directly referenced by the program and therefore should not be garbage-collected. Root chunks are also used by the garbage collector when scanning for chunk references.
When an object is to be freed, edgehtml!MemoryProtection::HeapFree() is called, which in turn calls chakra!MemProtectHeapUnrootAndZero().
Chakra!MemProtectHeapUnrootAndZero() attempts to locate the Block where the object’s chunk is, zero-out the chunk and then clear the root flag of the chunk. By clearing the root flag, the chunk will become a candidate for garbage collection and will be reclaimed if no references to it are found by the garbage collector (more on this below).
Once the total size of the unrooted chunks reaches a dynamically computed threshold value, garbage collection will be triggered via chakra!MemProtectHeap::Collect(). The garbage collection — a complicated process of which only the core functions are described here — will perform a mark-and-sweep operation to reclaim unreferenced unrooted chunks. Some parts of the mark-and-sweep operation are executed on a separate thread (chakra!Memory::Recycler::ThreadProc), which is notified via chakra!Memory::Recycler::StartConcurrent().
In the marking phase, the mark bit for all chunks is first cleared and all root chunks are marked (via chakra!Memory::Recycler::BackgroundResetMarks()). Then the root chunks (via chakra!Memory::Recycler:: ScanImplicitRoots()), registers and stack (via chakra!MemProtectHeap::FindRoots()) are scanned for chunk pointers. Referenced chunks found in the scan are marked. Chunks that are not marked after the marking phase will eventually be made available for reallocation.
Similar to Memory Protector, MemGC will further reduce the number of exploitable use-after-free vulnerabilities in Edge and IE. However, MemGC is also a complex mechanism with a custom heap management and garbage collection scheme. Attackers take advantage of complexity by looking at attack vectors that had been inadvertently introduced or attack techniques that were unwittingly made possible. Needless to say, MemGC deserves scrutiny to identify and eventually improve its potential weaknesses.
As mentioned at the start of this blog post, MemGC is one of the topics recently discussed in my Black Hat USA 2015 presentation. If you are interested in understanding the attack surface and exploit mitigations in EdgeHTML, please check out my slide deck and watch this video with my colleague Chris Poulin. For an even deeper dive into the subject, please download my white paper, Understanding the Attack Surface and Attack Resilience of Project Spartan’s (Edge) New EdgeHTML Rendering Engine.