Skip to content

Commit 3d2925b

Browse files
authored
[win/asan] AllocateMemoryForTrampoline within 2 GB of the module's base address (#108822)
Since we may copy code (see CopyInstructions) to the trampoline which could reference data inside the original module, we really want the trampoline to be within 2 GB of not just the original function, but within anything that function may have rip-relative accesses to, i.e. within 2 GB of that function's whole module. This fixes interception failures like the following scenario: 1. Intercept `CreateProcess` in kernel32.dll, allocating a trampoline region right after 2. Start intercepting `memcpy` in the main executable, which is loaded at a lower address than kernel32.dll, but still within 2 GB of the trampoline region so we keep using it. 3. Try to copy instructions from `memcpy` to the trampoline. Turns out one instruction references data that is more than 2GB away from the trampoline, so it can't be relocated. 4. The process exits due to a CHECK failure (Full story at https://crbug.com/341936875#comment45 and following.)
1 parent 9d3ab1c commit 3d2925b

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

compiler-rt/lib/interception/interception_win.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
#include "sanitizer_common/sanitizer_platform.h"
131131
#define WIN32_LEAN_AND_MEAN
132132
#include <windows.h>
133+
#include <psapi.h>
133134

134135
namespace __interception {
135136

@@ -385,7 +386,30 @@ void TestOnlyReleaseTrampolineRegions() {
385386
}
386387
}
387388

388-
static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) {
389+
static uptr AllocateMemoryForTrampoline(uptr func_address, size_t size) {
390+
uptr image_address = func_address;
391+
392+
#if SANITIZER_WINDOWS64
393+
// Allocate memory after the module (DLL or EXE file), but within 2GB
394+
// of the start of the module so that any address within the module can be
395+
// referenced with PC-relative operands.
396+
// This allows us to not just jump to the trampoline with a PC-relative
397+
// offset, but to relocate any instructions that we copy to the trampoline
398+
// which have references to the original module. If we can't find the base
399+
// address of the module (e.g. if func_address is in mmap'ed memory), just
400+
// use func_address as is.
401+
HMODULE module;
402+
if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
403+
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
404+
(LPCWSTR)func_address, &module)) {
405+
MODULEINFO module_info;
406+
if (::GetModuleInformation(::GetCurrentProcess(), module,
407+
&module_info, sizeof(module_info))) {
408+
image_address = (uptr)module_info.lpBaseOfDll;
409+
}
410+
}
411+
#endif
412+
389413
// Find a region within 2G with enough space to allocate |size| bytes.
390414
TrampolineMemoryRegion *region = nullptr;
391415
for (size_t bucket = 0; bucket < kMaxTrampolineRegion; ++bucket) {

0 commit comments

Comments
 (0)