[compiler-rt] 3d2925b - [win/asan] AllocateMemoryForTrampoline within 2 GB of the module's base address (#108822)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 17 23:58:17 PDT 2024


Author: Hans
Date: 2024-09-18T08:58:14+02:00
New Revision: 3d2925b9de0d60694a9f28edd2419f8eed34f1a1

URL: https://github.com/llvm/llvm-project/commit/3d2925b9de0d60694a9f28edd2419f8eed34f1a1
DIFF: https://github.com/llvm/llvm-project/commit/3d2925b9de0d60694a9f28edd2419f8eed34f1a1.diff

LOG: [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.)

Added: 
    

Modified: 
    compiler-rt/lib/interception/interception_win.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp
index a638e66eccee58..a0ff124a89c9ed 100644
--- a/compiler-rt/lib/interception/interception_win.cpp
+++ b/compiler-rt/lib/interception/interception_win.cpp
@@ -130,6 +130,7 @@
 #include "sanitizer_common/sanitizer_platform.h"
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
+#include <psapi.h>
 
 namespace __interception {
 
@@ -385,7 +386,30 @@ void TestOnlyReleaseTrampolineRegions() {
   }
 }
 
-static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) {
+static uptr AllocateMemoryForTrampoline(uptr func_address, size_t size) {
+  uptr image_address = func_address;
+
+#if SANITIZER_WINDOWS64
+  // Allocate memory after the module (DLL or EXE file), but within 2GB
+  // of the start of the module so that any address within the module can be
+  // referenced with PC-relative operands.
+  // This allows us to not just jump to the trampoline with a PC-relative
+  // offset, but to relocate any instructions that we copy to the trampoline
+  // which have references to the original module. If we can't find the base
+  // address of the module (e.g. if func_address is in mmap'ed memory), just
+  // use func_address as is.
+  HMODULE module;
+  if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                           GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                           (LPCWSTR)func_address, &module)) {
+    MODULEINFO module_info;
+    if (::GetModuleInformation(::GetCurrentProcess(), module,
+                                &module_info, sizeof(module_info))) {
+      image_address = (uptr)module_info.lpBaseOfDll;
+    }
+  }
+#endif
+
   // Find a region within 2G with enough space to allocate |size| bytes.
   TrampolineMemoryRegion *region = nullptr;
   for (size_t bucket = 0; bucket < kMaxTrampolineRegion; ++bucket) {


        


More information about the llvm-commits mailing list