1309124Sdim//===-- asan_win.cpp 2193323Sed//------------------------------------------------------===//> 3193323Sed// 4193323Sed// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5193323Sed// See https://llvm.org/LICENSE.txt for license information. 6193323Sed// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7193323Sed// 8193323Sed//===----------------------------------------------------------------------===// 9193323Sed// 10193323Sed// This file is a part of AddressSanitizer, an address sanity checker. 11193323Sed// 12193323Sed// Windows-specific details. 13193323Sed//===----------------------------------------------------------------------===// 14193323Sed 15193323Sed#include "sanitizer_common/sanitizer_platform.h" 16193323Sed#if SANITIZER_WINDOWS 17276479Sdim# define WIN32_LEAN_AND_MEAN 18261991Sdim# include <stdlib.h> 19276479Sdim# include <windows.h> 20193323Sed 21249423Sdim# include "asan_interceptors.h" 22249423Sdim# include "asan_internal.h" 23276479Sdim# include "asan_mapping.h" 24249423Sdim# include "asan_report.h" 25249423Sdim# include "asan_stack.h" 26288943Sdim# include "asan_thread.h" 27288943Sdim# include "sanitizer_common/sanitizer_libc.h" 28226633Sdim# include "sanitizer_common/sanitizer_mutex.h" 29288943Sdim# include "sanitizer_common/sanitizer_win.h" 30224145Sdim# include "sanitizer_common/sanitizer_win_defs.h" 31193323Sed 32288943Sdimusing namespace __asan; 33193323Sed 34210299Sedextern "C" { 35210299SedSANITIZER_INTERFACE_ATTRIBUTE 36210299Sedint __asan_should_detect_stack_use_after_return() { 37210299Sed __asan_init(); 38226633Sdim return __asan_option_detect_stack_use_after_return; 39210299Sed} 40210299Sed 41234353SdimSANITIZER_INTERFACE_ATTRIBUTE 42234353Sdimuptr __asan_get_shadow_memory_dynamic_address() { 43234353Sdim __asan_init(); 44234353Sdim return __asan_shadow_memory_dynamic_address; 45234353Sdim} 46234353Sdim} // extern "C" 47239462Sdim 48234353Sdim// ---------------------- Windows-specific interceptors ---------------- {{{ 49234353Sdimstatic LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; 50234353Sdimstatic LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler; 51234353Sdim 52276479Sdimextern "C" SANITIZER_INTERFACE_ATTRIBUTE long __asan_unhandled_exception_filter( 53234353Sdim EXCEPTION_POINTERS *info) { 54210299Sed EXCEPTION_RECORD *exception_record = info->ExceptionRecord; 55276479Sdim CONTEXT *context = info->ContextRecord; 56210299Sed 57210299Sed // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. 58210299Sed 59234353Sdim SignalContext sig(exception_record, context); 60234353Sdim ReportDeadlySignal(sig); 61234353Sdim UNREACHABLE("returned from reporting deadly signal"); 62234353Sdim} 63210299Sed 64210299Sed// Wrapper SEH Handler. If the exception should be handled by asan, we call 65210299Sed// __asan_unhandled_exception_filter, otherwise, we execute the user provided 66296417Sdim// exception handler or the default. 67234353Sdimstatic long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { 68234353Sdim DWORD exception_code = info->ExceptionRecord->ExceptionCode; 69210299Sed if (__sanitizer::IsHandledDeadlyException(exception_code)) 70234353Sdim return __asan_unhandled_exception_filter(info); 71210299Sed if (user_seh_handler) 72234353Sdim return user_seh_handler(info); 73234353Sdim // Bubble out to the default exception filter. 74210299Sed if (default_seh_handler) 75210299Sed return default_seh_handler(info); 76210299Sed return EXCEPTION_CONTINUE_SEARCH; 77234353Sdim} 78296417Sdim 79234353SdimINTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter, 80234353Sdim LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) { 81234353Sdim CHECK(REAL(SetUnhandledExceptionFilter)); 82234353Sdim if (ExceptionFilter == &SEHHandler) 83296417Sdim return REAL(SetUnhandledExceptionFilter)(ExceptionFilter); 84234353Sdim // We record the user provided exception handler to be called for all the 85234353Sdim // exceptions unhandled by asan. 86234353Sdim Swap(ExceptionFilter, user_seh_handler); 87210299Sed return ExceptionFilter; 88210299Sed} 89296417Sdim 90296417SdimINTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) { 91296417Sdim CHECK(REAL(RtlRaiseException)); 92296417Sdim // This is a noreturn function, unless it's one of the exceptions raised to 93296417Sdim // communicate with the debugger, such as the one from OutputDebugString. 94296417Sdim if (ExceptionRecord->ExceptionCode != DBG_PRINTEXCEPTION_C) 95296417Sdim __asan_handle_no_return(); 96296417Sdim REAL(RtlRaiseException)(ExceptionRecord); 97296417Sdim} 98309124Sdim 99309124SdimINTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { 100309124Sdim CHECK(REAL(RaiseException)); 101309124Sdim __asan_handle_no_return(); 102309124Sdim REAL(RaiseException)(a, b, c, d); 103309124Sdim} 104296417Sdim 105296417Sdim#ifdef _WIN64 106296417Sdim 107296417SdimINTERCEPTOR_WINAPI(EXCEPTION_DISPOSITION, __C_specific_handler, 108296417Sdim _EXCEPTION_RECORD *a, void *b, _CONTEXT *c, 109195340Sed _DISPATCHER_CONTEXT *d) { 110195340Sed CHECK(REAL(__C_specific_handler)); 111195340Sed __asan_handle_no_return(); 112226633Sdim return REAL(__C_specific_handler)(a, b, c, d); 113195340Sed} 114195340Sed 115195340Sed#else 116195340Sed 117195340SedINTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { 118195340Sed CHECK(REAL(_except_handler3)); 119195340Sed __asan_handle_no_return(); 120195340Sed return REAL(_except_handler3)(a, b, c, d); 121193323Sed} 122234353Sdim 123234353Sdim#if ASAN_DYNAMIC 124234353Sdim// This handler is named differently in -MT and -MD CRTs. 125234353Sdim#define _except_handler4 _except_handler4_common 126234353Sdim#endif 127234353SdimINTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { 128234353Sdim CHECK(REAL(_except_handler4)); 129234353Sdim __asan_handle_no_return(); 130193323Sed return REAL(_except_handler4)(a, b, c, d); 131195340Sed} 132193323Sed#endif 133193323Sed 134193323Sedstruct ThreadStartParams { 135193323Sed thread_callback_t start_routine; 136193323Sed void *arg; 137193323Sed}; 138193323Sed 139193323Sedstatic thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { 140193323Sed AsanThread *t = (AsanThread *)arg; 141193323Sed SetCurrentThread(t); 142193323Sed t->ThreadStart(GetTid()); 143193323Sed 144193323Sed ThreadStartParams params; 145193323Sed t->GetStartData(params); 146193323Sed 147210299Sed auto res = (*params.start_routine)(params.arg); 148193323Sed t->Destroy(); // POSIX calls this from TSD destructor. 149195340Sed return res; 150198090Srdivacky} 151210299Sed 152210299SedINTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security, 153193323Sed SIZE_T stack_size, LPTHREAD_START_ROUTINE start_routine, 154210299Sed void *arg, DWORD thr_flags, DWORD *tid) { 155210299Sed // Strict init-order checking is thread-hostile. 156210299Sed if (flags()->strict_init_order) 157210299Sed StopInitOrderChecking(); 158296417Sdim GET_STACK_TRACE_THREAD; 159210299Sed // FIXME: The CreateThread interceptor is not the same as a pthread_create 160210299Sed // one. This is a bandaid fix for PR22025. 161193323Sed bool detached = false; // FIXME: how can we determine it on Windows? 162193323Sed u32 current_tid = GetCurrentTidOrInvalid(); 163210299Sed ThreadStartParams params = {start_routine, arg}; 164193323Sed AsanThread *t = AsanThread::Create(params, current_tid, &stack, detached); 165296417Sdim return REAL(CreateThread)(security, stack_size, asan_thread_start, t, 166210299Sed thr_flags, tid); 167193323Sed} 168193323Sed 169193323Sed// }}} 170193323Sed 171195340Sednamespace __asan { 172195340Sed 173193323Sedvoid InitializePlatformInterceptors() { 174193323Sed __interception::SetErrorReportCallback(Report); 175193323Sed 176193323Sed // The interceptors were not designed to be removable, so we have to keep this 177193323Sed // module alive for the life of the process. 178193323Sed HMODULE pinned; 179193323Sed CHECK(GetModuleHandleExW( 180195340Sed GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, 181195340Sed (LPCWSTR)&InitializePlatformInterceptors, &pinned)); 182195340Sed 183195340Sed ASAN_INTERCEPT_FUNC(CreateThread); 184193323Sed ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter); 185193323Sed 186204792Srdivacky#ifdef _WIN64 187204792Srdivacky ASAN_INTERCEPT_FUNC(__C_specific_handler); 188204792Srdivacky#else 189204792Srdivacky ASAN_INTERCEPT_FUNC(_except_handler3); 190193323Sed ASAN_INTERCEPT_FUNC(_except_handler4); 191193323Sed#endif 192296417Sdim 193193323Sed // Try to intercept kernel32!RaiseException, and if that fails, intercept 194193323Sed // ntdll!RtlRaiseException instead. 195193323Sed if (!::__interception::OverrideFunction("RaiseException", 196195340Sed (uptr)WRAP(RaiseException), 197204642Srdivacky (uptr *)&REAL(RaiseException))) { 198261991Sdim CHECK(::__interception::OverrideFunction("RtlRaiseException", 199309124Sdim (uptr)WRAP(RtlRaiseException), 200204642Srdivacky (uptr *)&REAL(RtlRaiseException))); 201204642Srdivacky } 202296417Sdim} 203204642Srdivacky 204204642Srdivackyvoid InstallAtExitCheckLeaks() {} 205204642Srdivacky 206204642Srdivackyvoid InstallAtForkHandler() {} 207204642Srdivacky 208296417Sdimvoid AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 209204642Srdivacky UNIMPLEMENTED(); 210204642Srdivacky} 211193323Sed 212226633Sdimvoid FlushUnneededASanShadowMemory(uptr p, uptr size) { 213261991Sdim // Only asan on 64-bit Windows supports committing shadow memory on demand. 214202878Srdivacky#if SANITIZER_WINDOWS64 215204642Srdivacky // Since asan's mapping is compacting, the shadow chunk may be 216193323Sed // not page-aligned, so we only flush the page-aligned portion. 217193323Sed ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); 218193323Sed#endif 219193323Sed} 220193323Sed 221204642Srdivacky// ---------------------- TSD ---------------- {{{ 222193323Sedstatic bool tsd_key_inited = false; 223193323Sed 224193323Sedstatic __declspec(thread) void *fake_tsd = 0; 225193323Sed 226288943Sdim// https://docs.microsoft.com/en-us/windows/desktop/api/winternl/ns-winternl-_teb 227288943Sdim// "[This structure may be altered in future versions of Windows. Applications 228288943Sdim// should use the alternate functions listed in this topic.]" 229193323Sedtypedef struct _TEB { 230198090Srdivacky PVOID Reserved1[12]; 231193323Sed // PVOID ThreadLocalStoragePointer; is here, at the last field in Reserved1. 232193323Sed PVOID ProcessEnvironmentBlock; 233198090Srdivacky PVOID Reserved2[399]; 234198090Srdivacky BYTE Reserved3[1952]; 235207618Srdivacky PVOID TlsSlots[64]; 236198090Srdivacky BYTE Reserved4[8]; 237198090Srdivacky PVOID Reserved5[26]; 238198090Srdivacky PVOID ReservedForOle; 239193323Sed PVOID Reserved6[4]; 240193323Sed PVOID TlsExpansionSlots; 241198090Srdivacky} TEB, *PTEB; 242198090Srdivacky 243193323Sedconstexpr size_t TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET = 11; 244198090SrdivackyBOOL IsTlsInitialized() { 245198090Srdivacky PTEB teb = (PTEB)NtCurrentTeb(); 246198090Srdivacky return teb->Reserved1[TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET] != 247296417Sdim nullptr; 248198090Srdivacky} 249198090Srdivacky 250198090Srdivackyvoid AsanTSDInit(void (*destructor)(void *tsd)) { 251198090Srdivacky // FIXME: we're ignoring the destructor for now. 252198090Srdivacky tsd_key_inited = true; 253198090Srdivacky} 254296417Sdim 255296417Sdimvoid *AsanTSDGet() { 256198090Srdivacky CHECK(tsd_key_inited); 257198090Srdivacky return IsTlsInitialized() ? fake_tsd : nullptr; 258193323Sed} 259193323Sed 260193323Sedvoid AsanTSDSet(void *tsd) { 261193323Sed CHECK(tsd_key_inited); 262193323Sed fake_tsd = tsd; 263198090Srdivacky} 264288943Sdim 265288943Sdimvoid PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); } 266288943Sdim// }}} 267288943Sdim 268296417Sdim// ---------------------- Various stuff ---------------- {{{ 269288943Sdimvoid *AsanDoesNotSupportStaticLinkage() { return 0; } 270296417Sdim 271288943Sdimuptr FindDynamicShadowStart() { 272288943Sdim return MapDynamicShadow(MemToShadowSize(kHighMemEnd), ASAN_SHADOW_SCALE, 273193323Sed /*min_shadow_base_alignment*/ 0, kHighMemEnd); 274198090Srdivacky} 275193323Sed 276193323Sedvoid AsanCheckDynamicRTPrereqs() {} 277193323Sed 278198090Srdivackyvoid AsanCheckIncompatibleRT() {} 279207618Srdivacky 280276479Sdimvoid AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } 281193323Sed 282193323Sedbool PlatformUnpoisonStacks() { return false; } 283193323Sed 284198090Srdivacky#if SANITIZER_WINDOWS64 285276479Sdim// Exception handler for dealing with shadow memory. 286193323Sedstatic LONG CALLBACK 287261991SdimShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) { 288261991Sdim uptr page_size = GetPageSizeCached(); 289193323Sed // Only handle access violations. 290193323Sed if (exception_pointers->ExceptionRecord->ExceptionCode != 291193323Sed EXCEPTION_ACCESS_VIOLATION || 292193323Sed exception_pointers->ExceptionRecord->NumberParameters < 2) { 293193323Sed __asan_handle_no_return(); 294193323Sed return EXCEPTION_CONTINUE_SEARCH; 295198090Srdivacky } 296198090Srdivacky 297198090Srdivacky // Only handle access violations that land within the shadow memory. 298193323Sed uptr addr = 299198090Srdivacky (uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]); 300226633Sdim 301198090Srdivacky // Check valid shadow range. 302198090Srdivacky if (!AddrIsInShadow(addr)) { 303198090Srdivacky __asan_handle_no_return(); 304198090Srdivacky return EXCEPTION_CONTINUE_SEARCH; 305198090Srdivacky } 306198090Srdivacky 307198090Srdivacky // This is an access violation while trying to read from the shadow. Commit 308198090Srdivacky // the relevant page and let execution continue. 309198090Srdivacky 310207618Srdivacky // Determine the address of the page that is being accessed. 311198090Srdivacky uptr page = RoundDownTo(addr, page_size); 312198090Srdivacky 313198090Srdivacky // Commit the page. 314205407Srdivacky uptr result = 315198090Srdivacky (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE); 316210299Sed if (result != page) 317205407Srdivacky return EXCEPTION_CONTINUE_SEARCH; 318205407Srdivacky 319198090Srdivacky // The page mapping succeeded, so continue execution as usual. 320210299Sed return EXCEPTION_CONTINUE_EXECUTION; 321198090Srdivacky} 322198090Srdivacky 323198090Srdivacky#endif 324198090Srdivacky 325198090Srdivackyvoid InitializePlatformExceptionHandlers() { 326198090Srdivacky#if SANITIZER_WINDOWS64 327198090Srdivacky // On Win64, we map memory on demand with access violation handler. 328198090Srdivacky // Install our exception handler. 329226633Sdim CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler)); 330198090Srdivacky#endif 331198090Srdivacky} 332198090Srdivacky 333198090Srdivackybool IsSystemHeapAddress(uptr addr) { 334198090Srdivacky return ::HeapValidate(GetProcessHeap(), 0, (void *)addr) != FALSE; 335198090Srdivacky} 336198090Srdivacky 337207618Srdivacky// We want to install our own exception handler (EH) to print helpful reports 338198090Srdivacky// on access violations and whatnot. Unfortunately, the CRT initializers assume 339198090Srdivacky// they are run before any user code and drop any previously-installed EHs on 340221345Sdim// the floor, so we can't install our handler inside __asan_init. 341261991Sdim// (See crt0dat.c in the CRT sources for the details) 342198090Srdivacky// 343198090Srdivacky// Things get even more complicated with the dynamic runtime, as it finishes its 344210299Sed// initialization before the .exe module CRT begins to initialize. 345198090Srdivacky// 346198090Srdivacky// For the static runtime (-MT), it's enough to put a callback to 347198090Srdivacky// __asan_set_seh_filter in the last section for C initializers. 348198090Srdivacky// 349198090Srdivacky// For the dynamic runtime (-MD), we want link the same 350198090Srdivacky// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter 351198090Srdivacky// will be called for each instrumented module. This ensures that at least one 352210299Sed// __asan_set_seh_filter call happens after the .exe module CRT is initialized. 353198090Srdivackyextern "C" SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_seh_filter() { 354198090Srdivacky // We should only store the previous handler if it's not our own handler in 355198090Srdivacky // order to avoid loops in the EH chain. 356198090Srdivacky auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler); 357198090Srdivacky if (prev_seh_handler != &SEHHandler) 358198090Srdivacky default_seh_handler = prev_seh_handler; 359198090Srdivacky return 0; 360198090Srdivacky} 361198090Srdivacky 362198090Srdivackybool HandleDlopenInit() { 363198090Srdivacky // Not supported on this platform. 364198090Srdivacky static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 365202878Srdivacky "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 366198090Srdivacky return false; 367198090Srdivacky} 368198090Srdivacky 369198090Srdivacky#if !ASAN_DYNAMIC 370193323Sed// The CRT runs initializers in this order: 371193323Sed// - C initializers, from XIA to XIZ 372193323Sed// - C++ initializers, from XCA to XCZ 373193323Sed// Prior to 2015, the CRT set the unhandled exception filter at priority XIY, 374193323Sed// near the end of C initialization. Starting in 2015, it was moved to the 375193323Sed// beginning of C++ initialization. We set our priority to XCAB to run 376193323Sed// immediately after the CRT runs. This way, our exception filter is called 377193323Sed// first and we can delegate to their filter if appropriate. 378193323Sed#pragma section(".CRT$XCAB", long, read) 379193323Sed__declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() = 380193323Sed __asan_set_seh_filter; 381193323Sed 382193323Sed// Piggyback on the TLS initialization callback directory to initialize asan as 383193323Sed// early as possible. Initializers in .CRT$XL* are called directly by ntdll, 384193323Sed// which run before the CRT. Users also add code to .CRT$XLC, so it's important 385198090Srdivacky// to run our initializers first. 386198090Srdivackystatic void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) { 387226633Sdim if (reason == DLL_PROCESS_ATTACH) 388226633Sdim __asan_init(); 389193323Sed} 390288943Sdim 391288943Sdim#pragma section(".CRT$XLAB", long, read) 392193323Sed__declspec(allocate(".CRT$XLAB")) void(NTAPI *__asan_tls_init)( 393198090Srdivacky void *, unsigned long, void *) = asan_thread_init; 394193323Sed#endif 395193323Sed 396198090Srdivackystatic void NTAPI asan_thread_exit(void *module, DWORD reason, void *reserved) { 397198090Srdivacky if (reason == DLL_THREAD_DETACH) { 398198090Srdivacky // Unpoison the thread's stack because the memory may be re-used. 399198090Srdivacky NT_TIB *tib = (NT_TIB *)NtCurrentTeb(); 400288943Sdim uptr stackSize = (uptr)tib->StackBase - (uptr)tib->StackLimit; 401261991Sdim __asan_unpoison_memory_region(tib->StackLimit, stackSize); 402200581Srdivacky } 403193323Sed} 404193323Sed 405193323Sed#pragma section(".CRT$XLY", long, read) 406193323Sed__declspec(allocate(".CRT$XLY")) void(NTAPI *__asan_tls_exit)( 407193323Sed void *, unsigned long, void *) = asan_thread_exit; 408198090Srdivacky 409198090SrdivackyWIN_FORCE_LINK(__asan_dso_reg_hook) 410198090Srdivacky 411203954Srdivacky// }}} 412261991Sdim} // namespace __asan 413203954Srdivacky 414203954Srdivacky#endif // SANITIZER_WINDOWS 415296417Sdim