168d75effSDimitry Andric //===-- asan_posix.cpp ----------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Posix-specific details.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h"
1568d75effSDimitry Andric #if SANITIZER_POSIX
1668d75effSDimitry Andric
1781ad6265SDimitry Andric # include <pthread.h>
1881ad6265SDimitry Andric # include <signal.h>
1981ad6265SDimitry Andric # include <stdlib.h>
2081ad6265SDimitry Andric # include <sys/resource.h>
2181ad6265SDimitry Andric # include <sys/time.h>
2281ad6265SDimitry Andric # include <unistd.h>
2381ad6265SDimitry Andric
2468d75effSDimitry Andric # include "asan_interceptors.h"
2581ad6265SDimitry Andric # include "asan_internal.h"
2668d75effSDimitry Andric # include "asan_mapping.h"
275ffd83dbSDimitry Andric # include "asan_poisoning.h"
2868d75effSDimitry Andric # include "asan_report.h"
2968d75effSDimitry Andric # include "asan_stack.h"
3081ad6265SDimitry Andric # include "lsan/lsan_common.h"
3168d75effSDimitry Andric # include "sanitizer_common/sanitizer_libc.h"
3268d75effSDimitry Andric # include "sanitizer_common/sanitizer_posix.h"
3368d75effSDimitry Andric # include "sanitizer_common/sanitizer_procmaps.h"
3468d75effSDimitry Andric
3568d75effSDimitry Andric namespace __asan {
3668d75effSDimitry Andric
AsanOnDeadlySignal(int signo,void * siginfo,void * context)3768d75effSDimitry Andric void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
3868d75effSDimitry Andric StartReportDeadlySignal();
3968d75effSDimitry Andric SignalContext sig(siginfo, context);
4068d75effSDimitry Andric ReportDeadlySignal(sig);
4168d75effSDimitry Andric }
4268d75effSDimitry Andric
PlatformUnpoisonStacks()435ffd83dbSDimitry Andric bool PlatformUnpoisonStacks() {
445ffd83dbSDimitry Andric stack_t signal_stack;
455ffd83dbSDimitry Andric CHECK_EQ(0, sigaltstack(nullptr, &signal_stack));
465ffd83dbSDimitry Andric uptr sigalt_bottom = (uptr)signal_stack.ss_sp;
475ffd83dbSDimitry Andric uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size);
485ffd83dbSDimitry Andric // If we're executing on the signal alternate stack AND the Linux flag
495ffd83dbSDimitry Andric // SS_AUTODISARM was used, then we cannot get the signal alternate stack
505ffd83dbSDimitry Andric // bounds from sigaltstack -- sigaltstack's output looks just as if no
515ffd83dbSDimitry Andric // alternate stack has ever been set up.
525ffd83dbSDimitry Andric // We're always unpoisoning the signal alternate stack to support jumping
535ffd83dbSDimitry Andric // between the default stack and signal alternate stack.
545ffd83dbSDimitry Andric if (signal_stack.ss_flags != SS_DISABLE)
555ffd83dbSDimitry Andric UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt");
565ffd83dbSDimitry Andric
575ffd83dbSDimitry Andric if (signal_stack.ss_flags != SS_ONSTACK)
585ffd83dbSDimitry Andric return false;
595ffd83dbSDimitry Andric
60fe6060f1SDimitry Andric // Since we're on the signal alternate stack, we cannot find the DEFAULT
615ffd83dbSDimitry Andric // stack bottom using a local variable.
625ffd83dbSDimitry Andric uptr default_bottom, tls_addr, tls_size, stack_size;
635ffd83dbSDimitry Andric GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
645ffd83dbSDimitry Andric &tls_size);
655ffd83dbSDimitry Andric UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
665ffd83dbSDimitry Andric return true;
675ffd83dbSDimitry Andric }
685ffd83dbSDimitry Andric
6968d75effSDimitry Andric // ---------------------- TSD ---------------- {{{1
7068d75effSDimitry Andric
7168d75effSDimitry Andric #if SANITIZER_NETBSD && !ASAN_DYNAMIC
7268d75effSDimitry Andric // Thread Static Data cannot be used in early static ASan init on NetBSD.
7368d75effSDimitry Andric // Reuse the Asan TSD API for compatibility with existing code
7468d75effSDimitry Andric // with an alternative implementation.
7568d75effSDimitry Andric
7668d75effSDimitry Andric static void (*tsd_destructor)(void *tsd) = nullptr;
7768d75effSDimitry Andric
7868d75effSDimitry Andric struct tsd_key {
tsd_key__asan::tsd_key7968d75effSDimitry Andric tsd_key() : key(nullptr) {}
~tsd_key__asan::tsd_key8068d75effSDimitry Andric ~tsd_key() {
8168d75effSDimitry Andric CHECK(tsd_destructor);
8268d75effSDimitry Andric if (key)
8368d75effSDimitry Andric (*tsd_destructor)(key);
8468d75effSDimitry Andric }
8568d75effSDimitry Andric void *key;
8668d75effSDimitry Andric };
8768d75effSDimitry Andric
8868d75effSDimitry Andric static thread_local struct tsd_key key;
8968d75effSDimitry Andric
AsanTSDInit(void (* destructor)(void * tsd))9068d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
9168d75effSDimitry Andric CHECK(!tsd_destructor);
9268d75effSDimitry Andric tsd_destructor = destructor;
9368d75effSDimitry Andric }
9468d75effSDimitry Andric
AsanTSDGet()9568d75effSDimitry Andric void *AsanTSDGet() {
9668d75effSDimitry Andric CHECK(tsd_destructor);
9768d75effSDimitry Andric return key.key;
9868d75effSDimitry Andric }
9968d75effSDimitry Andric
AsanTSDSet(void * tsd)10068d75effSDimitry Andric void AsanTSDSet(void *tsd) {
10168d75effSDimitry Andric CHECK(tsd_destructor);
10268d75effSDimitry Andric CHECK(tsd);
10368d75effSDimitry Andric CHECK(!key.key);
10468d75effSDimitry Andric key.key = tsd;
10568d75effSDimitry Andric }
10668d75effSDimitry Andric
PlatformTSDDtor(void * tsd)10768d75effSDimitry Andric void PlatformTSDDtor(void *tsd) {
10868d75effSDimitry Andric CHECK(tsd_destructor);
10968d75effSDimitry Andric CHECK_EQ(key.key, tsd);
11068d75effSDimitry Andric key.key = nullptr;
11168d75effSDimitry Andric // Make sure that signal handler can not see a stale current thread pointer.
11268d75effSDimitry Andric atomic_signal_fence(memory_order_seq_cst);
11368d75effSDimitry Andric AsanThread::TSDDtor(tsd);
11468d75effSDimitry Andric }
11568d75effSDimitry Andric #else
11668d75effSDimitry Andric static pthread_key_t tsd_key;
11768d75effSDimitry Andric static bool tsd_key_inited = false;
AsanTSDInit(void (* destructor)(void * tsd))11868d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) {
11968d75effSDimitry Andric CHECK(!tsd_key_inited);
12068d75effSDimitry Andric tsd_key_inited = true;
12168d75effSDimitry Andric CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));
12268d75effSDimitry Andric }
12368d75effSDimitry Andric
AsanTSDGet()12468d75effSDimitry Andric void *AsanTSDGet() {
12568d75effSDimitry Andric CHECK(tsd_key_inited);
12668d75effSDimitry Andric return pthread_getspecific(tsd_key);
12768d75effSDimitry Andric }
12868d75effSDimitry Andric
AsanTSDSet(void * tsd)12968d75effSDimitry Andric void AsanTSDSet(void *tsd) {
13068d75effSDimitry Andric CHECK(tsd_key_inited);
13168d75effSDimitry Andric pthread_setspecific(tsd_key, tsd);
13268d75effSDimitry Andric }
13368d75effSDimitry Andric
PlatformTSDDtor(void * tsd)13468d75effSDimitry Andric void PlatformTSDDtor(void *tsd) {
13568d75effSDimitry Andric AsanThreadContext *context = (AsanThreadContext *)tsd;
13668d75effSDimitry Andric if (context->destructor_iterations > 1) {
13768d75effSDimitry Andric context->destructor_iterations--;
13868d75effSDimitry Andric CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
13968d75effSDimitry Andric return;
14068d75effSDimitry Andric }
1415f757f3fSDimitry Andric # if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
1425f757f3fSDimitry Andric SANITIZER_SOLARIS
1435f757f3fSDimitry Andric // After this point it's unsafe to execute signal handlers which may be
1445f757f3fSDimitry Andric // instrumented. It's probably not just a Linux issue.
1455f757f3fSDimitry Andric BlockSignals();
1465f757f3fSDimitry Andric # endif
14768d75effSDimitry Andric AsanThread::TSDDtor(tsd);
14868d75effSDimitry Andric }
14968d75effSDimitry Andric # endif
15081ad6265SDimitry Andric
BeforeFork()151*cb14a3feSDimitry Andric static void BeforeFork() {
1525f757f3fSDimitry Andric if (CAN_SANITIZE_LEAKS) {
1535f757f3fSDimitry Andric __lsan::LockGlobal();
1545f757f3fSDimitry Andric }
1555f757f3fSDimitry Andric // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
1565f757f3fSDimitry Andric // stuff we need.
1575f757f3fSDimitry Andric __lsan::LockThreads();
1585f757f3fSDimitry Andric __lsan::LockAllocator();
159*cb14a3feSDimitry Andric StackDepotLockBeforeFork();
160*cb14a3feSDimitry Andric }
161*cb14a3feSDimitry Andric
AfterFork(bool fork_child)162*cb14a3feSDimitry Andric static void AfterFork(bool fork_child) {
163*cb14a3feSDimitry Andric StackDepotUnlockAfterFork(fork_child);
1645f757f3fSDimitry Andric // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
1655f757f3fSDimitry Andric // the stuff we need.
1665f757f3fSDimitry Andric __lsan::UnlockAllocator();
1675f757f3fSDimitry Andric __lsan::UnlockThreads();
1685f757f3fSDimitry Andric if (CAN_SANITIZE_LEAKS) {
1695f757f3fSDimitry Andric __lsan::UnlockGlobal();
1705f757f3fSDimitry Andric }
171*cb14a3feSDimitry Andric }
172*cb14a3feSDimitry Andric
InstallAtForkHandler()173*cb14a3feSDimitry Andric void InstallAtForkHandler() {
174*cb14a3feSDimitry Andric # if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE
175*cb14a3feSDimitry Andric return; // FIXME: Implement FutexWait.
176*cb14a3feSDimitry Andric # endif
177*cb14a3feSDimitry Andric pthread_atfork(
178*cb14a3feSDimitry Andric &BeforeFork, []() { AfterFork(/* fork_child= */ false); },
179*cb14a3feSDimitry Andric []() { AfterFork(/* fork_child= */ true); });
1805f757f3fSDimitry Andric }
1815f757f3fSDimitry Andric
InstallAtExitCheckLeaks()18281ad6265SDimitry Andric void InstallAtExitCheckLeaks() {
18381ad6265SDimitry Andric if (CAN_SANITIZE_LEAKS) {
18481ad6265SDimitry Andric if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
18581ad6265SDimitry Andric if (flags()->halt_on_error)
18681ad6265SDimitry Andric Atexit(__lsan::DoLeakCheck);
18781ad6265SDimitry Andric else
18881ad6265SDimitry Andric Atexit(__lsan::DoRecoverableLeakCheckVoid);
18981ad6265SDimitry Andric }
19081ad6265SDimitry Andric }
19181ad6265SDimitry Andric }
19281ad6265SDimitry Andric
19368d75effSDimitry Andric } // namespace __asan
19468d75effSDimitry Andric
19568d75effSDimitry Andric #endif // SANITIZER_POSIX
196