107 lines
3.9 KiB
Diff
107 lines
3.9 KiB
Diff
From 69ebac7ad6ae1db9bb19cf3a19ea978af6034ca3 Mon Sep 17 00:00:00 2001
|
|
From: Hans Wennborg <hans@hanshq.net>
|
|
Date: Fri, 20 Dec 2024 11:03:17 +0100
|
|
Subject: [PATCH] [win/asan] Don't intercept memset etc. in ntdll (#120397)
|
|
|
|
When ntdll was added to the list of of "interesting DLLs" list (in
|
|
d58230b9dcb3b312a2da8f874daa0cc8dc27da9b), the intention was not to
|
|
intercept the "mini CRT" functions it exports. OverrideFunction would
|
|
only intercept the *first* function it found when searching the list of
|
|
DLLs, and ntdll was put last in that list.
|
|
|
|
However, after 42cdfbcf3e92466754c175cb0e1e237e9f66749e,
|
|
OverrideFunction intercepts *all* matching functions in those DLLs. As
|
|
a side-effect, the runtime would now intercept functions like memset
|
|
etc. also in ntdll.
|
|
|
|
This causes a problem when ntdll-internal functions like
|
|
RtlDispatchException call the intercepted memset, which tries to
|
|
inspect uncommitted shadow memory, raising an exception, and getting
|
|
stuck in that loop until the stack overflows.
|
|
|
|
Since we never intended to intercept ntdll's memset etc., the simplest
|
|
fix seems to be to actively ignore ntdll when intercepting those
|
|
functions.
|
|
|
|
Fixes #114793
|
|
---
|
|
.../lib/interception/interception_win.cpp | 32 ++++++++++++++++---
|
|
1 file changed, 28 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp
|
|
index 8e9d9462b005..4ad440d95da4 100644
|
|
--- a/compiler-rt/lib/interception/interception_win.cpp
|
|
+++ b/compiler-rt/lib/interception/interception_win.cpp
|
|
@@ -208,6 +208,18 @@ static char* _strchr(char* str, char c) {
|
|
return nullptr;
|
|
}
|
|
|
|
+static int _strcmp(const char *s1, const char *s2) {
|
|
+ while (true) {
|
|
+ unsigned c1 = *s1;
|
|
+ unsigned c2 = *s2;
|
|
+ if (c1 != c2) return (c1 < c2) ? -1 : 1;
|
|
+ if (c1 == 0) break;
|
|
+ s1++;
|
|
+ s2++;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void _memset(void *p, int value, size_t sz) {
|
|
for (size_t i = 0; i < sz; ++i)
|
|
((char*)p)[i] = (char)value;
|
|
@@ -971,8 +983,7 @@ static void **InterestingDLLsAvailable() {
|
|
"libc++.dll", // libc++
|
|
"libunwind.dll", // libunwind
|
|
# endif
|
|
- // NTDLL should go last as it exports some functions that we should
|
|
- // override in the CRT [presumably only used internally].
|
|
+ // NTDLL must go last as it gets special treatment in OverrideFunction.
|
|
"ntdll.dll",
|
|
NULL
|
|
};
|
|
@@ -1029,7 +1040,7 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
|
|
|
|
for (DWORD i = 0; i < exports->NumberOfNames; i++) {
|
|
RVAPtr<char> name(module, names[i]);
|
|
- if (!strcmp(func_name, name)) {
|
|
+ if (!_strcmp(func_name, name)) {
|
|
DWORD index = ordinals[i];
|
|
RVAPtr<char> func(module, functions[index]);
|
|
|
|
@@ -1067,9 +1078,22 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
|
|
|
|
bool OverrideFunction(
|
|
const char *func_name, uptr new_func, uptr *orig_old_func) {
|
|
+ static const char *kNtDllIgnore[] = {
|
|
+ "memcmp", "memcpy", "memmove", "memset"
|
|
+ };
|
|
+
|
|
bool hooked = false;
|
|
void **DLLs = InterestingDLLsAvailable();
|
|
for (size_t i = 0; DLLs[i]; ++i) {
|
|
+ if (DLLs[i + 1] == nullptr) {
|
|
+ // This is the last DLL, i.e. NTDLL. It exports some functions that
|
|
+ // we only want to override in the CRT.
|
|
+ for (const char *ignored : kNtDllIgnore) {
|
|
+ if (_strcmp(func_name, ignored) == 0)
|
|
+ return hooked;
|
|
+ }
|
|
+ }
|
|
+
|
|
uptr func_addr = InternalGetProcAddress(DLLs[i], func_name);
|
|
if (func_addr &&
|
|
OverrideFunction(func_addr, new_func, orig_old_func)) {
|
|
@@ -1123,7 +1147,7 @@ bool OverrideImportedFunction(const char *module_to_patch,
|
|
RVAPtr<IMAGE_IMPORT_BY_NAME> import_by_name(
|
|
module, name_table->u1.ForwarderString);
|
|
const char *funcname = &import_by_name->Name[0];
|
|
- if (strcmp(funcname, function_name) == 0)
|
|
+ if (_strcmp(funcname, function_name) == 0)
|
|
break;
|
|
}
|
|
}
|
|
--
|
|
2.42.0.windows.2
|
|
|