1353944Sdim//===-- asan_win.cpp ------------------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker.
10353944Sdim//
11353944Sdim// Windows-specific details.
12353944Sdim//===----------------------------------------------------------------------===//
13353944Sdim
14353944Sdim#include "sanitizer_common/sanitizer_platform.h"
15353944Sdim#if SANITIZER_WINDOWS
16353944Sdim#define WIN32_LEAN_AND_MEAN
17353944Sdim#include <windows.h>
18353944Sdim
19353944Sdim#include <stdlib.h>
20353944Sdim
21353944Sdim#include "asan_interceptors.h"
22353944Sdim#include "asan_internal.h"
23353944Sdim#include "asan_mapping.h"
24353944Sdim#include "asan_report.h"
25353944Sdim#include "asan_stack.h"
26353944Sdim#include "asan_thread.h"
27353944Sdim#include "sanitizer_common/sanitizer_libc.h"
28353944Sdim#include "sanitizer_common/sanitizer_mutex.h"
29353944Sdim#include "sanitizer_common/sanitizer_win.h"
30353944Sdim#include "sanitizer_common/sanitizer_win_defs.h"
31353944Sdim
32353944Sdimusing namespace __asan;
33353944Sdim
34353944Sdimextern "C" {
35353944SdimSANITIZER_INTERFACE_ATTRIBUTE
36353944Sdimint __asan_should_detect_stack_use_after_return() {
37353944Sdim  __asan_init();
38353944Sdim  return __asan_option_detect_stack_use_after_return;
39353944Sdim}
40353944Sdim
41353944SdimSANITIZER_INTERFACE_ATTRIBUTE
42353944Sdimuptr __asan_get_shadow_memory_dynamic_address() {
43353944Sdim  __asan_init();
44353944Sdim  return __asan_shadow_memory_dynamic_address;
45353944Sdim}
46353944Sdim}  // extern "C"
47353944Sdim
48353944Sdim// ---------------------- Windows-specific interceptors ---------------- {{{
49353944Sdimstatic LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
50353944Sdimstatic LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler;
51353944Sdim
52353944Sdimextern "C" SANITIZER_INTERFACE_ATTRIBUTE
53353944Sdimlong __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) {
54353944Sdim  EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
55353944Sdim  CONTEXT *context = info->ContextRecord;
56353944Sdim
57353944Sdim  // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
58353944Sdim
59353944Sdim  SignalContext sig(exception_record, context);
60353944Sdim  ReportDeadlySignal(sig);
61353944Sdim  UNREACHABLE("returned from reporting deadly signal");
62353944Sdim}
63353944Sdim
64353944Sdim// Wrapper SEH Handler. If the exception should be handled by asan, we call
65353944Sdim// __asan_unhandled_exception_filter, otherwise, we execute the user provided
66353944Sdim// exception handler or the default.
67353944Sdimstatic long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
68353944Sdim  DWORD exception_code = info->ExceptionRecord->ExceptionCode;
69353944Sdim  if (__sanitizer::IsHandledDeadlyException(exception_code))
70353944Sdim    return __asan_unhandled_exception_filter(info);
71353944Sdim  if (user_seh_handler)
72353944Sdim    return user_seh_handler(info);
73353944Sdim  // Bubble out to the default exception filter.
74353944Sdim  if (default_seh_handler)
75353944Sdim    return default_seh_handler(info);
76353944Sdim  return EXCEPTION_CONTINUE_SEARCH;
77353944Sdim}
78353944Sdim
79353944SdimINTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter,
80353944Sdim                   LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) {
81353944Sdim  CHECK(REAL(SetUnhandledExceptionFilter));
82353944Sdim  if (ExceptionFilter == &SEHHandler)
83353944Sdim    return REAL(SetUnhandledExceptionFilter)(ExceptionFilter);
84353944Sdim  // We record the user provided exception handler to be called for all the
85353944Sdim  // exceptions unhandled by asan.
86353944Sdim  Swap(ExceptionFilter, user_seh_handler);
87353944Sdim  return ExceptionFilter;
88353944Sdim}
89353944Sdim
90353944SdimINTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) {
91353944Sdim  CHECK(REAL(RtlRaiseException));
92353944Sdim  // This is a noreturn function, unless it's one of the exceptions raised to
93353944Sdim  // communicate with the debugger, such as the one from OutputDebugString.
94353944Sdim  if (ExceptionRecord->ExceptionCode != DBG_PRINTEXCEPTION_C)
95353944Sdim    __asan_handle_no_return();
96353944Sdim  REAL(RtlRaiseException)(ExceptionRecord);
97353944Sdim}
98353944Sdim
99353944SdimINTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
100353944Sdim  CHECK(REAL(RaiseException));
101353944Sdim  __asan_handle_no_return();
102353944Sdim  REAL(RaiseException)(a, b, c, d);
103353944Sdim}
104353944Sdim
105353944Sdim#ifdef _WIN64
106353944Sdim
107353944SdimINTERCEPTOR_WINAPI(EXCEPTION_DISPOSITION, __C_specific_handler,
108353944Sdim                   _EXCEPTION_RECORD *a, void *b, _CONTEXT *c,
109353944Sdim                   _DISPATCHER_CONTEXT *d) {
110353944Sdim  CHECK(REAL(__C_specific_handler));
111353944Sdim  __asan_handle_no_return();
112353944Sdim  return REAL(__C_specific_handler)(a, b, c, d);
113353944Sdim}
114353944Sdim
115353944Sdim#else
116353944Sdim
117353944SdimINTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
118353944Sdim  CHECK(REAL(_except_handler3));
119353944Sdim  __asan_handle_no_return();
120353944Sdim  return REAL(_except_handler3)(a, b, c, d);
121353944Sdim}
122353944Sdim
123353944Sdim#if ASAN_DYNAMIC
124353944Sdim// This handler is named differently in -MT and -MD CRTs.
125353944Sdim#define _except_handler4 _except_handler4_common
126353944Sdim#endif
127353944SdimINTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
128353944Sdim  CHECK(REAL(_except_handler4));
129353944Sdim  __asan_handle_no_return();
130353944Sdim  return REAL(_except_handler4)(a, b, c, d);
131353944Sdim}
132353944Sdim#endif
133353944Sdim
134353944Sdimstatic thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
135353944Sdim  AsanThread *t = (AsanThread *)arg;
136353944Sdim  SetCurrentThread(t);
137353944Sdim  return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
138353944Sdim}
139353944Sdim
140353944SdimINTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security,
141353944Sdim                   SIZE_T stack_size, LPTHREAD_START_ROUTINE start_routine,
142353944Sdim                   void *arg, DWORD thr_flags, DWORD *tid) {
143353944Sdim  // Strict init-order checking is thread-hostile.
144353944Sdim  if (flags()->strict_init_order)
145353944Sdim    StopInitOrderChecking();
146353944Sdim  GET_STACK_TRACE_THREAD;
147353944Sdim  // FIXME: The CreateThread interceptor is not the same as a pthread_create
148353944Sdim  // one.  This is a bandaid fix for PR22025.
149353944Sdim  bool detached = false;  // FIXME: how can we determine it on Windows?
150353944Sdim  u32 current_tid = GetCurrentTidOrInvalid();
151353944Sdim  AsanThread *t =
152353944Sdim      AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
153353944Sdim  return REAL(CreateThread)(security, stack_size, asan_thread_start, t,
154353944Sdim                            thr_flags, tid);
155353944Sdim}
156353944Sdim
157353944Sdim// }}}
158353944Sdim
159353944Sdimnamespace __asan {
160353944Sdim
161353944Sdimvoid InitializePlatformInterceptors() {
162353944Sdim  // The interceptors were not designed to be removable, so we have to keep this
163353944Sdim  // module alive for the life of the process.
164353944Sdim  HMODULE pinned;
165353944Sdim  CHECK(GetModuleHandleExW(
166353944Sdim      GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
167353944Sdim      (LPCWSTR)&InitializePlatformInterceptors, &pinned));
168353944Sdim
169353944Sdim  ASAN_INTERCEPT_FUNC(CreateThread);
170353944Sdim  ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
171353944Sdim
172353944Sdim#ifdef _WIN64
173353944Sdim  ASAN_INTERCEPT_FUNC(__C_specific_handler);
174353944Sdim#else
175353944Sdim  ASAN_INTERCEPT_FUNC(_except_handler3);
176353944Sdim  ASAN_INTERCEPT_FUNC(_except_handler4);
177353944Sdim#endif
178353944Sdim
179353944Sdim  // Try to intercept kernel32!RaiseException, and if that fails, intercept
180353944Sdim  // ntdll!RtlRaiseException instead.
181353944Sdim  if (!::__interception::OverrideFunction("RaiseException",
182353944Sdim                                          (uptr)WRAP(RaiseException),
183353944Sdim                                          (uptr *)&REAL(RaiseException))) {
184353944Sdim    CHECK(::__interception::OverrideFunction("RtlRaiseException",
185353944Sdim                                             (uptr)WRAP(RtlRaiseException),
186353944Sdim                                             (uptr *)&REAL(RtlRaiseException)));
187353944Sdim  }
188353944Sdim}
189353944Sdim
190353944Sdimvoid AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
191353944Sdim  UNIMPLEMENTED();
192353944Sdim}
193353944Sdim
194353944Sdim// ---------------------- TSD ---------------- {{{
195353944Sdimstatic bool tsd_key_inited = false;
196353944Sdim
197353944Sdimstatic __declspec(thread) void *fake_tsd = 0;
198353944Sdim
199353944Sdim// https://docs.microsoft.com/en-us/windows/desktop/api/winternl/ns-winternl-_teb
200353944Sdim// "[This structure may be altered in future versions of Windows. Applications
201353944Sdim// should use the alternate functions listed in this topic.]"
202353944Sdimtypedef struct _TEB {
203353944Sdim  PVOID Reserved1[12];
204353944Sdim  // PVOID ThreadLocalStoragePointer; is here, at the last field in Reserved1.
205353944Sdim  PVOID ProcessEnvironmentBlock;
206353944Sdim  PVOID Reserved2[399];
207353944Sdim  BYTE Reserved3[1952];
208353944Sdim  PVOID TlsSlots[64];
209353944Sdim  BYTE Reserved4[8];
210353944Sdim  PVOID Reserved5[26];
211353944Sdim  PVOID ReservedForOle;
212353944Sdim  PVOID Reserved6[4];
213353944Sdim  PVOID TlsExpansionSlots;
214353944Sdim} TEB, *PTEB;
215353944Sdim
216353944Sdimconstexpr size_t TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET = 11;
217353944SdimBOOL IsTlsInitialized() {
218353944Sdim  PTEB teb = (PTEB)NtCurrentTeb();
219353944Sdim  return teb->Reserved1[TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET] !=
220353944Sdim         nullptr;
221353944Sdim}
222353944Sdim
223353944Sdimvoid AsanTSDInit(void (*destructor)(void *tsd)) {
224353944Sdim  // FIXME: we're ignoring the destructor for now.
225353944Sdim  tsd_key_inited = true;
226353944Sdim}
227353944Sdim
228353944Sdimvoid *AsanTSDGet() {
229353944Sdim  CHECK(tsd_key_inited);
230353944Sdim  return IsTlsInitialized() ? fake_tsd : nullptr;
231353944Sdim}
232353944Sdim
233353944Sdimvoid AsanTSDSet(void *tsd) {
234353944Sdim  CHECK(tsd_key_inited);
235353944Sdim  fake_tsd = tsd;
236353944Sdim}
237353944Sdim
238353944Sdimvoid PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); }
239353944Sdim// }}}
240353944Sdim
241353944Sdim// ---------------------- Various stuff ---------------- {{{
242353944Sdimvoid *AsanDoesNotSupportStaticLinkage() {
243353944Sdim#if defined(_DEBUG)
244353944Sdim#error Please build the runtime with a non-debug CRT: /MD or /MT
245353944Sdim#endif
246353944Sdim  return 0;
247353944Sdim}
248353944Sdim
249353944Sdimuptr FindDynamicShadowStart() {
250353944Sdim  uptr granularity = GetMmapGranularity();
251353944Sdim  uptr alignment = 8 * granularity;
252353944Sdim  uptr left_padding = granularity;
253353944Sdim  uptr space_size = kHighShadowEnd + left_padding;
254353944Sdim  uptr shadow_start = FindAvailableMemoryRange(space_size, alignment,
255353944Sdim                                               granularity, nullptr, nullptr);
256353944Sdim  CHECK_NE((uptr)0, shadow_start);
257353944Sdim  CHECK(IsAligned(shadow_start, alignment));
258353944Sdim  return shadow_start;
259353944Sdim}
260353944Sdim
261353944Sdimvoid AsanCheckDynamicRTPrereqs() {}
262353944Sdim
263353944Sdimvoid AsanCheckIncompatibleRT() {}
264353944Sdim
265353944Sdimvoid ReadContextStack(void *context, uptr *stack, uptr *ssize) {
266353944Sdim  UNIMPLEMENTED();
267353944Sdim}
268353944Sdim
269353944Sdimvoid AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); }
270353944Sdim
271353944Sdim#if SANITIZER_WINDOWS64
272353944Sdim// Exception handler for dealing with shadow memory.
273353944Sdimstatic LONG CALLBACK
274353944SdimShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {
275353944Sdim  uptr page_size = GetPageSizeCached();
276353944Sdim  // Only handle access violations.
277353944Sdim  if (exception_pointers->ExceptionRecord->ExceptionCode !=
278353944Sdim          EXCEPTION_ACCESS_VIOLATION ||
279353944Sdim      exception_pointers->ExceptionRecord->NumberParameters < 2) {
280353944Sdim    __asan_handle_no_return();
281353944Sdim    return EXCEPTION_CONTINUE_SEARCH;
282353944Sdim  }
283353944Sdim
284353944Sdim  // Only handle access violations that land within the shadow memory.
285353944Sdim  uptr addr =
286353944Sdim      (uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]);
287353944Sdim
288353944Sdim  // Check valid shadow range.
289353944Sdim  if (!AddrIsInShadow(addr)) {
290353944Sdim    __asan_handle_no_return();
291353944Sdim    return EXCEPTION_CONTINUE_SEARCH;
292353944Sdim  }
293353944Sdim
294353944Sdim  // This is an access violation while trying to read from the shadow. Commit
295353944Sdim  // the relevant page and let execution continue.
296353944Sdim
297353944Sdim  // Determine the address of the page that is being accessed.
298353944Sdim  uptr page = RoundDownTo(addr, page_size);
299353944Sdim
300353944Sdim  // Commit the page.
301353944Sdim  uptr result =
302353944Sdim      (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE);
303353944Sdim  if (result != page)
304353944Sdim    return EXCEPTION_CONTINUE_SEARCH;
305353944Sdim
306353944Sdim  // The page mapping succeeded, so continue execution as usual.
307353944Sdim  return EXCEPTION_CONTINUE_EXECUTION;
308353944Sdim}
309353944Sdim
310353944Sdim#endif
311353944Sdim
312353944Sdimvoid InitializePlatformExceptionHandlers() {
313353944Sdim#if SANITIZER_WINDOWS64
314353944Sdim  // On Win64, we map memory on demand with access violation handler.
315353944Sdim  // Install our exception handler.
316353944Sdim  CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler));
317353944Sdim#endif
318353944Sdim}
319353944Sdim
320353944Sdimbool IsSystemHeapAddress(uptr addr) {
321353944Sdim  return ::HeapValidate(GetProcessHeap(), 0, (void *)addr) != FALSE;
322353944Sdim}
323353944Sdim
324353944Sdim// We want to install our own exception handler (EH) to print helpful reports
325353944Sdim// on access violations and whatnot.  Unfortunately, the CRT initializers assume
326353944Sdim// they are run before any user code and drop any previously-installed EHs on
327353944Sdim// the floor, so we can't install our handler inside __asan_init.
328353944Sdim// (See crt0dat.c in the CRT sources for the details)
329353944Sdim//
330353944Sdim// Things get even more complicated with the dynamic runtime, as it finishes its
331353944Sdim// initialization before the .exe module CRT begins to initialize.
332353944Sdim//
333353944Sdim// For the static runtime (-MT), it's enough to put a callback to
334353944Sdim// __asan_set_seh_filter in the last section for C initializers.
335353944Sdim//
336353944Sdim// For the dynamic runtime (-MD), we want link the same
337353944Sdim// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
338353944Sdim// will be called for each instrumented module.  This ensures that at least one
339353944Sdim// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
340353944Sdimextern "C" SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_seh_filter() {
341353944Sdim  // We should only store the previous handler if it's not our own handler in
342353944Sdim  // order to avoid loops in the EH chain.
343353944Sdim  auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
344353944Sdim  if (prev_seh_handler != &SEHHandler)
345353944Sdim    default_seh_handler = prev_seh_handler;
346353944Sdim  return 0;
347353944Sdim}
348353944Sdim
349353944Sdimbool HandleDlopenInit() {
350353944Sdim  // Not supported on this platform.
351353944Sdim  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
352353944Sdim                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
353353944Sdim  return false;
354353944Sdim}
355353944Sdim
356353944Sdim#if !ASAN_DYNAMIC
357353944Sdim// The CRT runs initializers in this order:
358353944Sdim// - C initializers, from XIA to XIZ
359353944Sdim// - C++ initializers, from XCA to XCZ
360353944Sdim// Prior to 2015, the CRT set the unhandled exception filter at priority XIY,
361353944Sdim// near the end of C initialization. Starting in 2015, it was moved to the
362353944Sdim// beginning of C++ initialization. We set our priority to XCAB to run
363353944Sdim// immediately after the CRT runs. This way, our exception filter is called
364353944Sdim// first and we can delegate to their filter if appropriate.
365353944Sdim#pragma section(".CRT$XCAB", long, read)
366353944Sdim__declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() =
367353944Sdim    __asan_set_seh_filter;
368353944Sdim
369353944Sdim// Piggyback on the TLS initialization callback directory to initialize asan as
370353944Sdim// early as possible. Initializers in .CRT$XL* are called directly by ntdll,
371353944Sdim// which run before the CRT. Users also add code to .CRT$XLC, so it's important
372353944Sdim// to run our initializers first.
373353944Sdimstatic void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) {
374353944Sdim  if (reason == DLL_PROCESS_ATTACH)
375353944Sdim    __asan_init();
376353944Sdim}
377353944Sdim
378353944Sdim#pragma section(".CRT$XLAB", long, read)
379353944Sdim__declspec(allocate(".CRT$XLAB")) void(NTAPI *__asan_tls_init)(
380353944Sdim    void *, unsigned long, void *) = asan_thread_init;
381353944Sdim#endif
382353944Sdim
383353944Sdimstatic void NTAPI asan_thread_exit(void *module, DWORD reason, void *reserved) {
384353944Sdim  if (reason == DLL_THREAD_DETACH) {
385353944Sdim    // Unpoison the thread's stack because the memory may be re-used.
386353944Sdim    NT_TIB *tib = (NT_TIB *)NtCurrentTeb();
387353944Sdim    uptr stackSize = (uptr)tib->StackBase - (uptr)tib->StackLimit;
388353944Sdim    __asan_unpoison_memory_region(tib->StackLimit, stackSize);
389353944Sdim  }
390353944Sdim}
391353944Sdim
392353944Sdim#pragma section(".CRT$XLY", long, read)
393353944Sdim__declspec(allocate(".CRT$XLY")) void(NTAPI *__asan_tls_exit)(
394353944Sdim    void *, unsigned long, void *) = asan_thread_exit;
395353944Sdim
396353944SdimWIN_FORCE_LINK(__asan_dso_reg_hook)
397353944Sdim
398353944Sdim// }}}
399353944Sdim}  // namespace __asan
400353944Sdim
401353944Sdim#endif  // SANITIZER_WINDOWS
402