llvmorg-20-init-16060-g69ebac7ad6ae.patch (3967B)
1 From 69ebac7ad6ae1db9bb19cf3a19ea978af6034ca3 Mon Sep 17 00:00:00 2001 2 From: Hans Wennborg <hans@hanshq.net> 3 Date: Fri, 20 Dec 2024 11:03:17 +0100 4 Subject: [PATCH] [win/asan] Don't intercept memset etc. in ntdll (#120397) 5 6 When ntdll was added to the list of of "interesting DLLs" list (in 7 d58230b9dcb3b312a2da8f874daa0cc8dc27da9b), the intention was not to 8 intercept the "mini CRT" functions it exports. OverrideFunction would 9 only intercept the *first* function it found when searching the list of 10 DLLs, and ntdll was put last in that list. 11 12 However, after 42cdfbcf3e92466754c175cb0e1e237e9f66749e, 13 OverrideFunction intercepts *all* matching functions in those DLLs. As 14 a side-effect, the runtime would now intercept functions like memset 15 etc. also in ntdll. 16 17 This causes a problem when ntdll-internal functions like 18 RtlDispatchException call the intercepted memset, which tries to 19 inspect uncommitted shadow memory, raising an exception, and getting 20 stuck in that loop until the stack overflows. 21 22 Since we never intended to intercept ntdll's memset etc., the simplest 23 fix seems to be to actively ignore ntdll when intercepting those 24 functions. 25 26 Fixes #114793 27 --- 28 .../lib/interception/interception_win.cpp | 32 ++++++++++++++++--- 29 1 file changed, 28 insertions(+), 4 deletions(-) 30 31 diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp 32 index 8e9d9462b005..4ad440d95da4 100644 33 --- a/compiler-rt/lib/interception/interception_win.cpp 34 +++ b/compiler-rt/lib/interception/interception_win.cpp 35 @@ -208,6 +208,18 @@ static char* _strchr(char* str, char c) { 36 return nullptr; 37 } 38 39 +static int _strcmp(const char *s1, const char *s2) { 40 + while (true) { 41 + unsigned c1 = *s1; 42 + unsigned c2 = *s2; 43 + if (c1 != c2) return (c1 < c2) ? -1 : 1; 44 + if (c1 == 0) break; 45 + s1++; 46 + s2++; 47 + } 48 + return 0; 49 +} 50 + 51 static void _memset(void *p, int value, size_t sz) { 52 for (size_t i = 0; i < sz; ++i) 53 ((char*)p)[i] = (char)value; 54 @@ -971,8 +983,7 @@ static void **InterestingDLLsAvailable() { 55 "libc++.dll", // libc++ 56 "libunwind.dll", // libunwind 57 # endif 58 - // NTDLL should go last as it exports some functions that we should 59 - // override in the CRT [presumably only used internally]. 60 + // NTDLL must go last as it gets special treatment in OverrideFunction. 61 "ntdll.dll", 62 NULL 63 }; 64 @@ -1029,7 +1040,7 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { 65 66 for (DWORD i = 0; i < exports->NumberOfNames; i++) { 67 RVAPtr<char> name(module, names[i]); 68 - if (!strcmp(func_name, name)) { 69 + if (!_strcmp(func_name, name)) { 70 DWORD index = ordinals[i]; 71 RVAPtr<char> func(module, functions[index]); 72 73 @@ -1067,9 +1078,22 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { 74 75 bool OverrideFunction( 76 const char *func_name, uptr new_func, uptr *orig_old_func) { 77 + static const char *kNtDllIgnore[] = { 78 + "memcmp", "memcpy", "memmove", "memset" 79 + }; 80 + 81 bool hooked = false; 82 void **DLLs = InterestingDLLsAvailable(); 83 for (size_t i = 0; DLLs[i]; ++i) { 84 + if (DLLs[i + 1] == nullptr) { 85 + // This is the last DLL, i.e. NTDLL. It exports some functions that 86 + // we only want to override in the CRT. 87 + for (const char *ignored : kNtDllIgnore) { 88 + if (_strcmp(func_name, ignored) == 0) 89 + return hooked; 90 + } 91 + } 92 + 93 uptr func_addr = InternalGetProcAddress(DLLs[i], func_name); 94 if (func_addr && 95 OverrideFunction(func_addr, new_func, orig_old_func)) { 96 @@ -1123,7 +1147,7 @@ bool OverrideImportedFunction(const char *module_to_patch, 97 RVAPtr<IMAGE_IMPORT_BY_NAME> import_by_name( 98 module, name_table->u1.ForwarderString); 99 const char *funcname = &import_by_name->Name[0]; 100 - if (strcmp(funcname, function_name) == 0) 101 + if (_strcmp(funcname, function_name) == 0) 102 break; 103 } 104 } 105 -- 106 2.42.0.windows.2