| Issue |
114793
|
| Summary |
memset interception in compiler-rt asan is incompatible with ntdll.dll 10.0.26100.2161 from Windows 11 24H2
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
yjugl
|
ntdll
===
[ntdll.dll 10.0.26100.2161](https://msdl.microsoft.com/download/symbols/ntdll.dll/6C29F8C2263000/ntdll.dll) from Windows 11 24H2 26100.2161 differs from previous versions of ntdll.dll in a subtle way.
Previously RtlDispatchException would almost directly reach into the vectored exception handlers:
```
// ntdll 10.0.19041.5007
push rbp
push rsi
push rdi
push r12
push r13
push r14
push r15
sub rsp, 1D0h
lea rbp, [rsp+40h]
mov qword ptr [rbp+1E0h], rbx
mov rax, qword ptr [ntdll!__security_cookie]
xor rax, rbp
mov qword ptr [rbp+180h], rax
mov rax, qword ptr gs:[60h]
xor ebx, ebx
mov r15, rdx
mov qword ptr [rbp+40h], rdx
mov rsi, rcx
mov byte ptr [rbp], bl
test dword ptr [rax+0BCh], 800000h
jne ntdll!RtlDispatchException+0x687c4
xor r8d, r8d
mov rdx, r15
mov rcx, rsi
call ntdll!RtlpCallVectoredHandlers
```
But now, two buffers of respective sizes 0x58 and 0xD8 are memset to zero before reaching into the vectored exception handlers:
```
// 10.0.26100.2161
ntdll!RtlDispatchException:
push rbp
push rsi
push rdi
push r12
push r13
push r14
push r15
sub rsp, 210h
lea rbp, [rsp+60h]
mov qword ptr [rbp+200h], rbx
mov rax, qword ptr [ntdll!__security_cookie]
xor rax, rbp
mov qword ptr [rbp+1A0h], rax
xor esi, esi
mov r15, rdx
mov rdi, rcx
mov dword ptr [rbp+20h], esi
xor edx, edx
lea rcx, [rbp+50h]
lea r8d, [rsi+50h]
// memset(something, 0, 0x50)
call ntdll!memset$thunk$772440563353939046
xor edx, edx
mov byte ptr [rbp], sil
mov r8d, 0D8h
mov qword ptr [rbp+8], rsi
lea rcx, [rbp+0C0h]
mov qword ptr [rbp+10h], rsi
mov qword ptr [rbp+18h], rsi
mov qword ptr [rbp+48h], rsi
mov qword ptr [rbp+28h], rsi
mov qword ptr [rbp+40h], rsi
// memset(something, 0, 0xD8)
call ntdll!memset$thunk$772440563353939046
mov rax, qword ptr gs:[60h]
test dword ptr [rax+0BCh], 800000h
je ntdll!RtlDispatchException+0xa0
cmp qword ptr [ntdll!RtlpExceptionLog2], rsi
mov byte ptr [rbp], 1
jne ntdll!RtlDispatchException+0x609
xor r8d, r8d
mov rdx, r15
mov rcx, rdi
call ntdll!RtlpCallVectoredHandlers
```
Now let me detail why we care here.
memset interception with ASAN
=====================
When compiler-rt ASAN instrumentation is in place, memset is replaced for instrumentation purposes. So any memset will go through:
```c++
#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
{ \
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
return internal_memset(dst, v, size); \
COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
if (common_flags()->intercept_intrin) \
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
return REAL(memset)(dst, v, size); \
}
```
Which, after following macros, uses:
```c++
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) \
do { \
uptr __offset = (uptr)(offset); \
uptr __size = (uptr)(size); \
uptr __bad = 0; \
if (UNLIKELY(__offset > __offset + __size)) { \
GET_STACK_TRACE_FATAL_HERE; \
ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
} \
if (UNLIKELY(!QuickCheckForUnpoisonedRegion(__offset, __size)) && \
(__bad = __asan_region_is_poisoned(__offset, __size))) { \
AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
bool suppressed = false; \
if (_ctx) { \
suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
if (!suppressed && HaveStackTraceBasedSuppressions()) { \
GET_STACK_TRACE_FATAL_HERE; \
suppressed = IsStackTraceSuppressed(&stack); \
} \
} \
if (!suppressed) { \
GET_CURRENT_PC_BP_SP; \
ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false); \
} \
} \
} while (0)
```
In particular, `__asan_region_is_poisoned` will access the shadow memory corresponding to the region that we memset, in order to check if the region is poisoned.
Shadow memory lazy commit on Windows
============================
On Windows, shadow memory pages are first allocated as `MEM_RESERVE`. They are dynamically turned to `MEM_COMMIT` on demand -- meaning that we rely on an exception handler `ShadowExceptionHandler` to change the status of the page when we fail to access a reserved shadow memory page because it is not yet commited.
Putting it together
============
The memset interception in ASAN is incompatible with ntdll 10.0.26100.2161. As soon as a first access violation gets raised because a shadow memory page is reserved but not committed, we immediately reach a new call to memset before we get a chance to reach the `ShadowExceptionHandler`. The new call to memset itself triggers a new access violation and a new call to memset, etc. This is a neverending cycle, until eventually we overflow the stack.
```c++
# Child-SP RetAddr Call Site
00 0000003e`f3000fa0 00007ffb`03adf0da clang_rt_asan_dynamic_x86_64!__asan_wrap_memset+0x18e [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc @ 87]
01 0000003e`f3001830 00007ffb`03c236de ntdll!RtlDispatchException+0x4a
02 0000003e`f3001a80 00007ffa`8c4c8632 ntdll!KiUserExceptionDispatch+0x2e
03 (Inline Function) --------`-------- clang_rt_asan_dynamic_x86_64!__asan::AddressIsPoisoned+0xe [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_mapping.h @ 395]
04 0000003e`f3002180 00007ffa`8c4c56a3 clang_rt_asan_dynamic_x86_64!__asan_region_is_poisoned+0xf2 [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_poisoning.cpp @ 189]
05 0000003e`f30021e0 00007ffb`03adf0da clang_rt_asan_dynamic_x86_64!__asan_wrap_memset+0x193 [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc @ 87]
06 0000003e`f3002a70 00007ffb`03c236de ntdll!RtlDispatchException+0x4a
07 0000003e`f3002cc0 00007ffa`8c4c8632 ntdll!KiUserExceptionDispatch+0x2e
08 (Inline Function) --------`-------- clang_rt_asan_dynamic_x86_64!__asan::AddressIsPoisoned+0xe [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_mapping.h @ 395]
09 0000003e`f30033c0 00007ffa`8c4c56a3 clang_rt_asan_dynamic_x86_64!__asan_region_is_poisoned+0xf2 [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_poisoning.cpp @ 189]
// ...
```
Related Firefox bug [here](https://bugzilla.mozilla.org/show_bug.cgi?id=1926680).
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs