Skip to content

Commit 69ebac7

Browse files
authored
[win/asan] Don't intercept memset etc. in ntdll (#120397)
When ntdll was added to the list of of "interesting DLLs" list (in d58230b), 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 42cdfbc, 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
1 parent e10cb44 commit 69ebac7

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

compiler-rt/lib/interception/interception_win.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,18 @@ static char* _strchr(char* str, char c) {
213213
return nullptr;
214214
}
215215

216+
static int _strcmp(const char *s1, const char *s2) {
217+
while (true) {
218+
unsigned c1 = *s1;
219+
unsigned c2 = *s2;
220+
if (c1 != c2) return (c1 < c2) ? -1 : 1;
221+
if (c1 == 0) break;
222+
s1++;
223+
s2++;
224+
}
225+
return 0;
226+
}
227+
216228
static void _memset(void *p, int value, size_t sz) {
217229
for (size_t i = 0; i < sz; ++i)
218230
((char*)p)[i] = (char)value;
@@ -1177,8 +1189,7 @@ static void **InterestingDLLsAvailable() {
11771189
"libc++.dll", // libc++
11781190
"libunwind.dll", // libunwind
11791191
# endif
1180-
// NTDLL should go last as it exports some functions that we should
1181-
// override in the CRT [presumably only used internally].
1192+
// NTDLL must go last as it gets special treatment in OverrideFunction.
11821193
"ntdll.dll",
11831194
NULL
11841195
};
@@ -1235,7 +1246,7 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
12351246

12361247
for (DWORD i = 0; i < exports->NumberOfNames; i++) {
12371248
RVAPtr<char> name(module, names[i]);
1238-
if (!strcmp(func_name, name)) {
1249+
if (!_strcmp(func_name, name)) {
12391250
DWORD index = ordinals[i];
12401251
RVAPtr<char> func(module, functions[index]);
12411252

@@ -1281,9 +1292,22 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
12811292

12821293
bool OverrideFunction(
12831294
const char *func_name, uptr new_func, uptr *orig_old_func) {
1295+
static const char *kNtDllIgnore[] = {
1296+
"memcmp", "memcpy", "memmove", "memset"
1297+
};
1298+
12841299
bool hooked = false;
12851300
void **DLLs = InterestingDLLsAvailable();
12861301
for (size_t i = 0; DLLs[i]; ++i) {
1302+
if (DLLs[i + 1] == nullptr) {
1303+
// This is the last DLL, i.e. NTDLL. It exports some functions that
1304+
// we only want to override in the CRT.
1305+
for (const char *ignored : kNtDllIgnore) {
1306+
if (_strcmp(func_name, ignored) == 0)
1307+
return hooked;
1308+
}
1309+
}
1310+
12871311
uptr func_addr = InternalGetProcAddress(DLLs[i], func_name);
12881312
if (func_addr &&
12891313
OverrideFunction(func_addr, new_func, orig_old_func)) {
@@ -1337,7 +1361,7 @@ bool OverrideImportedFunction(const char *module_to_patch,
13371361
RVAPtr<IMAGE_IMPORT_BY_NAME> import_by_name(
13381362
module, name_table->u1.ForwarderString);
13391363
const char *funcname = &import_by_name->Name[0];
1340-
if (strcmp(funcname, function_name) == 0)
1364+
if (_strcmp(funcname, function_name) == 0)
13411365
break;
13421366
}
13431367
}

0 commit comments

Comments
 (0)