Repository navigation
Conversation
…lloc interception Enable libafl_frida's ASan on Windows to catch heap out-of-bounds, use-after-free, and double-free against real allocator lifecycles (no byte-granular shadow needed): - Electric-fence guard-page allocator: page-aligned data with a PAGE_NOACCESS guard page so the first overrun / use-after-free write faults in the hardware. - Skip shadow-check emission on Windows (the guard page does OOB/UAF detection); emitting the shadow check re-enters handle_trap and deadlocks. - Intercept dealloc in the Stalker transformer: rewrite the target's call [__imp_HeapFree] to the free replacement, since RtlFreeHeap is a CFG dispatch stub and cannot be raw-jumped. dealloc then reaches release for UAF/double-free. - Use Backtrace::new_unresolved + Minimal verbosity in report_error to avoid a dbghelp symbol-resolution deadlock while holding the allocator lock. - try_lock the allocator in handle_trap (and clone metadata) to avoid lock poison. - Fix the Windows PE import enumeration (per-import IAT slot) for the HeapAlloc/ HeapFree IAT rewrites.
Contributor
Author
|
Dependency note: this change calls |
Collaborator
|
All in all it looks good. My only worry is that by getting rid of the "byte-granular" shadow, and relying only on guard pages, we will miss some errors. I don't know why you say that it doesn't work. In my initial testing it did, so far as I recall. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
libafl_frida'sAsanRuntimedid not detect heap memory errors on Windows for two compounding reasons:Byte-granular shadow is not available on Windows. The runtime's normal approach relies on a fixed 16 TiB shadow mapping plus per-access shadow checks; on Windows that mapping cannot be committed, so the instrumented memory accesses have nothing to validate against.
The Windows heap entry points are forwarders / CFG stubs, and the Stalker bypasses
Interceptor.RtlAllocateHeapis a forwarder tontdll!RtlAllocateHeap;RtlFreeHeapis a 5-byte forwarder stub whose target is a CFGpush [rip+...]; jmp [rip+...]dispatch stub. Under the Stalker, a recompiledcall [__imp_HeapAlloc]/call [__imp_HeapFree]gets re-resolved back to the original export, soInterceptor::replaceon those exports is never reached. Allocations/deallocations therefore bypass the ASan hooks entirely.Changes
Electric-fence allocator (Windows only)
On Windows the allocator now places each allocation so its data ends on a page boundary with an immediately-following
PAGE_NOACCESSguard page (reused blocks have that guard flipped back toPAGE_READWRITE). The first byte of a heap overflow or a write-after-free therefore faults in hardware, replacing the byte-granular shadow for the object's own bounds.Do not emit the shadow check on Windows
With the guard page doing overrun/use-after-free detection, the byte-granular shadow check is redundant and actively harmful: on a fault it re-enters
handle_trap, which blocks on the allocator lock and hangs resolving symbols. Emission is now gated to non-Windows targets.Raw detour on the resolved
RtlAllocateHeapBecause the Stalker re-routes
call [__imp_HeapAlloc]to the original export (bypassing theInterceptortrampoline), the runtime patches a plain absolute jump (mov rax, imm64; jmp rax) overRtlAllocateHeap's real entry, resolving any forwarder stub to its real target first. This guarantees every allocation lands on the fence.Dealloc interception in the Stalker transformer
RtlFreeHeapcannot be patched (forwarder -> CFG dispatch stub), so the free path is fixed in the transformer instead: when it emitscall [rip+disp]targeting the target image's__imp_HeapFreeIAT slot, it emits a direct call to the runtime's free replacement.HeapFreethen reachesAllocator::release, which flags double-free (metadata already released) and makes the freed page inaccessible for use-after-free.Avoid the dbghelp deadlock in
report_errorError reporting captured a resolved
Backtraceand printed at full verbosity; resolving symbols through dbghelp while holding the allocator lock deadlocks. It now capturesBacktrace::new_unresolved()and prints atVerbosity::Minimal.Locking in
handle_traphandle_trapnowtry_locks the allocator and clones out the metadata it needs, rather than blocking, since the interrupted in-process executor may still hold the allocator lock; this avoids a deadlock and a poisoned mutex.Windows import enumeration
enumerate_importsnow yields each import's own IAT slot (it could previously reuse one slot), so theHeapAlloc/HeapFreeIAT rewrites address the correct slots.Shutdown observer
A
FridaHelperShutdownObserverdeinitializes the runtimes on engine shutdown.