diff options
Diffstat (limited to 'compiler-rt')
17 files changed, 289 insertions, 87 deletions
diff --git a/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake index 53aa750..2040001 100644 --- a/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTAIXUtils.cmake @@ -34,12 +34,10 @@ macro(archive_aix_libatomic name libname) if(TARGET ${target}) file(MAKE_DIRECTORY ${output_dir}) add_custom_command(OUTPUT "${output_dir}/libatomic.so.1" - POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${target}>" "${output_dir}/libatomic.so.1" # If built with MODULE, F_LOADONLY is set. - # We have to remove this flag at POST_BUILD. COMMAND ${CMAKE_STRIP} -X32_64 -E "${output_dir}/libatomic.so.1" DEPENDS ${target}) diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp index c3ed252..d3fa953 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -28,7 +28,7 @@ static const u64 kAllocaRedzoneMask = 31UL; // For small size classes inline PoisonShadow for better performance. ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { CHECK(AddrIsAlignedByGranularity(ptr + size)); - u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr)); + u64* shadow = reinterpret_cast<u64*>(MemToShadow(ptr)); if (ASAN_SHADOW_SCALE == 3 && class_id <= 6) { // This code expects ASAN_SHADOW_SCALE=3. for (uptr i = 0; i < (((uptr)1) << class_id); i++) { @@ -47,7 +47,7 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { } } -FakeStack *FakeStack::Create(uptr stack_size_log) { +FakeStack* FakeStack::Create(uptr stack_size_log) { static uptr kMinStackSizeLog = 16; static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28); if (stack_size_log < kMinStackSizeLog) @@ -57,7 +57,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) { CHECK_LE(kMaxStackFrameSizeLog, stack_size_log); uptr size = RequiredSize(stack_size_log); uptr padded_size = size + kMaxStackFrameSize; - void *true_res = reinterpret_cast<void *>( + void* true_res = reinterpret_cast<void*>( flags()->uar_noreserve ? MmapNoReserveOrDie(padded_size, "FakeStack") : MmapOrDie(padded_size, "FakeStack")); // GetFrame() requires the property that @@ -66,20 +66,20 @@ FakeStack *FakeStack::Create(uptr stack_size_log) { // We didn't use MmapAlignedOrDieOnFatalError, because it requires that the // *size* is a power of 2, which is an overly strong condition. static_assert(alignof(FakeStack) <= kMaxStackFrameSize); - FakeStack *res = reinterpret_cast<FakeStack *>( + FakeStack* res = reinterpret_cast<FakeStack*>( RoundUpTo( (uptr)true_res + kFlagsOffset + SizeRequiredForFlags(stack_size_log), kMaxStackFrameSize) - kFlagsOffset - SizeRequiredForFlags(stack_size_log)); res->true_start = true_res; res->stack_size_log_ = stack_size_log; - u8 *p = reinterpret_cast<u8 *>(res); + u8* p = reinterpret_cast<u8*>(res); VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; " "mmapped %zdK, noreserve=%d, true_start: %p, start of first frame: " "0x%zx\n", - GetCurrentTidOrInvalid(), (void *)p, - (void *)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log, + GetCurrentTidOrInvalid(), (void*)p, + (void*)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log, size >> 10, flags()->uar_noreserve, res->true_start, res->GetFrame(stack_size_log, /*class_id*/ 0, /*pos*/ 0)); return res; @@ -109,14 +109,14 @@ void FakeStack::PoisonAll(u8 magic) { #if !defined(_MSC_VER) || defined(__clang__) ALWAYS_INLINE USED #endif -FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, - uptr real_stack) { + FakeFrame* FakeStack::Allocate(uptr stack_size_log, uptr class_id, + uptr real_stack) { CHECK_LT(class_id, kNumberOfSizeClasses); if (needs_gc_) GC(real_stack); - uptr &hint_position = hint_position_[class_id]; + uptr& hint_position = hint_position_[class_id]; const int num_iter = NumberOfFrames(stack_size_log, class_id); - u8 *flags = GetFlags(stack_size_log, class_id); + u8* flags = GetFlags(stack_size_log, class_id); for (int i = 0; i < num_iter; i++) { uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++); // This part is tricky. On one hand, checking and setting flags[pos] @@ -126,22 +126,24 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, // and so will not touch this particular byte. So, it is safe to do this // with regular non-atomic load and store (at least I was not able to make // this code crash). - if (flags[pos]) continue; + if (flags[pos]) + continue; flags[pos] = 1; - FakeFrame *res = reinterpret_cast<FakeFrame *>( - GetFrame(stack_size_log, class_id, pos)); + FakeFrame* res = + reinterpret_cast<FakeFrame*>(GetFrame(stack_size_log, class_id, pos)); res->real_stack = real_stack; *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos]; return res; } - return nullptr; // We are out of fake stack. + return nullptr; // We are out of fake stack. } -uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { +uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr* frame_beg, uptr* frame_end) { uptr stack_size_log = this->stack_size_log(); uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0)); uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log); - if (ptr < beg || ptr >= end) return 0; + if (ptr < beg || ptr >= end) + return 0; uptr class_id = (ptr - beg) >> stack_size_log; uptr base = beg + (class_id << stack_size_log); CHECK_LE(base, ptr); @@ -153,9 +155,7 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { return res; } -void FakeStack::HandleNoReturn() { - needs_gc_ = true; -} +void FakeStack::HandleNoReturn() { needs_gc_ = true; } // Hack: The statement below is not true if we take into account sigaltstack or // makecontext. It should be possible to make GC to discard wrong stack frame if @@ -170,7 +170,7 @@ void FakeStack::HandleNoReturn() { // We do it based on their 'real_stack' values -- everything that is lower // than the current real_stack is garbage. NOINLINE void FakeStack::GC(uptr real_stack) { - AsanThread *curr_thread = GetCurrentThread(); + AsanThread* curr_thread = GetCurrentThread(); if (!curr_thread) return; // Try again when we have a thread. auto top = curr_thread->stack_top(); @@ -179,12 +179,13 @@ NOINLINE void FakeStack::GC(uptr real_stack) { return; // Not the default stack. for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { - u8 *flags = GetFlags(stack_size_log(), class_id); + u8* flags = GetFlags(stack_size_log(), class_id); for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; i++) { - if (flags[i] == 0) continue; // not allocated. - FakeFrame *ff = reinterpret_cast<FakeFrame *>( - GetFrame(stack_size_log(), class_id, i)); + if (flags[i] == 0) + continue; // not allocated. + FakeFrame* ff = + reinterpret_cast<FakeFrame*>(GetFrame(stack_size_log(), class_id, i)); // GC only on the default stack. if (bottom < ff->real_stack && ff->real_stack < real_stack) { flags[i] = 0; @@ -197,14 +198,15 @@ NOINLINE void FakeStack::GC(uptr real_stack) { needs_gc_ = false; } -void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { +void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void* arg) { for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { - u8 *flags = GetFlags(stack_size_log(), class_id); + u8* flags = GetFlags(stack_size_log(), class_id); for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; i++) { - if (flags[i] == 0) continue; // not allocated. - FakeFrame *ff = reinterpret_cast<FakeFrame *>( - GetFrame(stack_size_log(), class_id, i)); + if (flags[i] == 0) + continue; // not allocated. + FakeFrame* ff = + reinterpret_cast<FakeFrame*>(GetFrame(stack_size_log(), class_id, i)); uptr begin = reinterpret_cast<uptr>(ff); callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg); } @@ -212,44 +214,51 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { } #if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA -static THREADLOCAL FakeStack *fake_stack_tls; +static THREADLOCAL FakeStack* fake_stack_tls; -FakeStack *GetTLSFakeStack() { - return fake_stack_tls; -} -void SetTLSFakeStack(FakeStack *fs) { - fake_stack_tls = fs; -} +static FakeStack* GetTLSFakeStack() { return fake_stack_tls; } +static void SetTLSFakeStack(FakeStack* fs) { fake_stack_tls = fs; } +void ResetTLSFakeStack() { fake_stack_tls = nullptr; } #else -FakeStack *GetTLSFakeStack() { return 0; } -void SetTLSFakeStack(FakeStack *fs) { } +static FakeStack* GetTLSFakeStack() { return nullptr; } +static void SetTLSFakeStack(FakeStack*) {} +void ResetTLSFakeStack() {} #endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA -static FakeStack *GetFakeStack() { - AsanThread *t = GetCurrentThread(); - if (!t) return nullptr; +static FakeStack* GetFakeStack() { + AsanThread* t = GetCurrentThread(); + if (!t) + return nullptr; return t->get_or_create_fake_stack(); } -static FakeStack *GetFakeStackFast() { - if (FakeStack *fs = GetTLSFakeStack()) +static FakeStack* GetFakeStackFast() { + FakeStack* fs = GetTLSFakeStack(); + if (LIKELY(fs)) return fs; if (!__asan_option_detect_stack_use_after_return) return nullptr; - return GetFakeStack(); + fs = GetFakeStack(); + if (LIKELY(fs)) + SetTLSFakeStack(fs); + return fs; } -static FakeStack *GetFakeStackFastAlways() { - if (FakeStack *fs = GetTLSFakeStack()) +static FakeStack* GetFakeStackFastAlways() { + FakeStack* fs = GetTLSFakeStack(); + if (LIKELY(fs)) return fs; - return GetFakeStack(); + fs = GetFakeStack(); + if (LIKELY(fs)) + SetTLSFakeStack(fs); + return fs; } static ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) { - FakeStack *fs = GetFakeStackFast(); + FakeStack* fs = GetFakeStackFast(); if (!fs) return 0; - FakeFrame *ff = + FakeFrame* ff = fs->Allocate(fs->stack_size_log(), class_id, GET_CURRENT_FRAME()); if (!ff) return 0; // Out of fake stack. @@ -259,10 +268,10 @@ static ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) { } static ALWAYS_INLINE uptr OnMallocAlways(uptr class_id, uptr size) { - FakeStack *fs = GetFakeStackFastAlways(); + FakeStack* fs = GetFakeStackFastAlways(); if (!fs) return 0; - FakeFrame *ff = + FakeFrame* ff = fs->Allocate(fs->stack_size_log(), class_id, GET_CURRENT_FRAME()); if (!ff) return 0; // Out of fake stack. @@ -276,17 +285,17 @@ static ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) { SetShadow(ptr, size, class_id, kMagic8); } -} // namespace __asan +} // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; #define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ - __asan_stack_malloc_##class_id(uptr size) { \ + __asan_stack_malloc_##class_id(uptr size) { \ return OnMalloc(class_id, size); \ } \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ - __asan_stack_malloc_always_##class_id(uptr size) { \ + __asan_stack_malloc_always_##class_id(uptr size) { \ return OnMallocAlways(class_id, size); \ } \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \ @@ -311,21 +320,25 @@ extern "C" { // -asan-use-after-return=never, after modal UAR flag lands // (https://github.com/google/sanitizers/issues/1394) SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_get_current_fake_stack() { return GetFakeStackFast(); } +void* __asan_get_current_fake_stack() { return GetFakeStackFast(); } SANITIZER_INTERFACE_ATTRIBUTE -void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, - void **end) { - FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack); - if (!fs) return nullptr; +void* __asan_addr_is_in_fake_stack(void* fake_stack, void* addr, void** beg, + void** end) { + FakeStack* fs = reinterpret_cast<FakeStack*>(fake_stack); + if (!fs) + return nullptr; uptr frame_beg, frame_end; - FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack( + FakeFrame* frame = reinterpret_cast<FakeFrame*>(fs->AddrIsInFakeStack( reinterpret_cast<uptr>(addr), &frame_beg, &frame_end)); - if (!frame) return nullptr; + if (!frame) + return nullptr; if (frame->magic != kCurrentStackFrameMagic) return nullptr; - if (beg) *beg = reinterpret_cast<void*>(frame_beg); - if (end) *end = reinterpret_cast<void*>(frame_end); + if (beg) + *beg = reinterpret_cast<void*>(frame_beg); + if (end) + *end = reinterpret_cast<void*>(frame_end); return reinterpret_cast<void*>(frame->real_stack); } @@ -344,9 +357,9 @@ void __asan_alloca_poison(uptr addr, uptr size) { SANITIZER_INTERFACE_ATTRIBUTE void __asan_allocas_unpoison(uptr top, uptr bottom) { - if ((!top) || (top > bottom)) return; - REAL(memset) - (reinterpret_cast<void *>(MemToShadow(top)), 0, - (bottom - top) / ASAN_SHADOW_GRANULARITY); + if ((!top) || (top > bottom)) + return; + REAL(memset)(reinterpret_cast<void*>(MemToShadow(top)), 0, + (bottom - top) / ASAN_SHADOW_GRANULARITY); } -} // extern "C" +} // extern "C" diff --git a/compiler-rt/lib/asan/asan_fake_stack.h b/compiler-rt/lib/asan/asan_fake_stack.h index 50706e6..593c137 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.h +++ b/compiler-rt/lib/asan/asan_fake_stack.h @@ -195,8 +195,7 @@ class FakeStack { void *true_start; }; -FakeStack *GetTLSFakeStack(); -void SetTLSFakeStack(FakeStack *fs); +void ResetTLSFakeStack(); } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp index 2627ae1..0ed58bb 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -163,7 +163,7 @@ void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, if (fake_stack_save) *fake_stack_save = fake_stack_; fake_stack_ = nullptr; - SetTLSFakeStack(nullptr); + ResetTLSFakeStack(); // if fake_stack_save is null, the fiber will die, delete the fakestack if (!fake_stack_save && current_fake_stack) current_fake_stack->Destroy(this->tid()); @@ -177,8 +177,8 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old, } if (fake_stack_save) { - SetTLSFakeStack(fake_stack_save); fake_stack_ = fake_stack_save; + ResetTLSFakeStack(); } if (bottom_old) @@ -242,7 +242,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { Max(stack_size_log, static_cast<uptr>(flags()->min_uar_stack_size_log)); fake_stack_ = FakeStack::Create(stack_size_log); DCHECK_EQ(GetCurrentThread(), this); - SetTLSFakeStack(fake_stack_); + ResetTLSFakeStack(); return fake_stack_; } return nullptr; diff --git a/compiler-rt/lib/asan/asan_thread.h b/compiler-rt/lib/asan/asan_thread.h index 12f0cc7..19b7f34 100644 --- a/compiler-rt/lib/asan/asan_thread.h +++ b/compiler-rt/lib/asan/asan_thread.h @@ -104,7 +104,7 @@ class AsanThread { if (!fake_stack_) return; FakeStack *t = fake_stack_; fake_stack_ = nullptr; - SetTLSFakeStack(nullptr); + ResetTLSFakeStack(); t->Destroy(tid); } diff --git a/compiler-rt/lib/builtins/cpu_model/x86.c b/compiler-rt/lib/builtins/cpu_model/x86.c index d91e13c..7ddfaa3 100644 --- a/compiler-rt/lib/builtins/cpu_model/x86.c +++ b/compiler-rt/lib/builtins/cpu_model/x86.c @@ -104,6 +104,7 @@ enum ProcessorSubtypes { INTEL_COREI7_PANTHERLAKE, AMDFAM1AH_ZNVER5, INTEL_COREI7_DIAMONDRAPIDS, + INTEL_COREI7_NOVALAKE, CPU_SUBTYPE_MAX }; @@ -646,6 +647,19 @@ static const char *getIntelProcessorTypeAndSubtype(unsigned Family, break; } break; + case 0x12: + switch (Model) { + case 0x1: + case 0x3: + CPU = "novalake"; + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_NOVALAKE; + break; + default: // Unknown family 0x12 CPU. + break; + } + break; + default: break; // Unknown. } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 3e82df4..ba85a0e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -390,6 +390,9 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid, void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); +bool IsSignalHandlerFromSanitizer(int signum); +bool SetSignalHandlerFromSanitizer(int signum, bool new_state); + // Construct a one-line string: // SUMMARY: SanitizerToolName: error_message // and pass it to __sanitizer_report_error_summary. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc index 650a458..5f44990 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -113,6 +113,11 @@ COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes, COMMON_FLAG(bool, allow_user_segv_handler, true, "Deprecated. True has no effect, use handle_sigbus=1. If false, " "handle_*=1 will be upgraded to handle_*=2.") +COMMON_FLAG(bool, cloak_sanitizer_signal_handlers, false, + "If set, signal/sigaction will pretend that sanitizers did not " + "preinstall any signal handlers. If the user subsequently installs " + "a signal handler, this will disable cloaking for the respective " + "signal.") COMMON_FLAG(bool, use_sigaltstack, true, "If set, uses alternate stack for signal handling.") COMMON_FLAG(bool, detect_deadlocks, true, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index b1eb200..8e5e879 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -47,6 +47,8 @@ typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); namespace __sanitizer { +[[maybe_unused]] static atomic_uint8_t signal_handler_is_from_sanitizer[64]; + u32 GetUid() { return getuid(); } @@ -210,6 +212,20 @@ void UnsetAlternateSignalStack() { UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); } +bool IsSignalHandlerFromSanitizer(int signum) { + return atomic_load(&signal_handler_is_from_sanitizer[signum], + memory_order_relaxed); +} + +bool SetSignalHandlerFromSanitizer(int signum, bool new_state) { + if (signum < 0 || static_cast<unsigned>(signum) >= + ARRAY_SIZE(signal_handler_is_from_sanitizer)) + return false; + + return atomic_exchange(&signal_handler_is_from_sanitizer[signum], new_state, + memory_order_relaxed); +} + static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { if (GetHandleSignalMode(signum) == kHandleSignalNo) return; @@ -223,6 +239,9 @@ static void MaybeInstallSigaction(int signum, if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); VReport(1, "Installed the sigaction for signal %d\n", signum); + + if (common_flags()->cloak_sanitizer_signal_handlers) + SetSignalHandlerFromSanitizer(signum, true); } void InstallDeadlySignalHandlers(SignalHandlerType handler) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc index 94e4e29..8511e4d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc @@ -45,6 +45,8 @@ using namespace __sanitizer; INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0; + + // TODO: support cloak_sanitizer_signal_handlers SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler); } #define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal) @@ -56,19 +58,55 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) { INTERCEPTOR(uptr, signal, int signum, uptr handler) { SIGNAL_INTERCEPTOR_ENTER(); if (GetHandleSignalMode(signum) == kHandleSignalExclusive) + // The user can neither view nor change the signal handler, regardless of + // the cloak_sanitizer_signal_handlers setting. This differs from + // sigaction(). return (uptr) nullptr; - SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); + + uptr ret = +[](auto signal, int signum, uptr handler) { + SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler); + }(signal, signum, handler); + + if (ret != sig_err && SetSignalHandlerFromSanitizer(signum, false)) + // If the user sets a signal handler, it becomes uncloaked, even if they + // reuse a sanitizer's signal handler. + ret = sig_dfl; + + return ret; } #define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal) INTERCEPTOR(int, sigaction_symname, int signum, const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) { SIGNAL_INTERCEPTOR_ENTER(); + if (GetHandleSignalMode(signum) == kHandleSignalExclusive) { if (!oldact) return 0; act = nullptr; + // If cloak_sanitizer_signal_handlers=true, the user can neither view nor + // change the signal handle. + // If false, the user can view but not change the signal handler. This + // differs from signal(). } - SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); + + int ret = +[](int signum, const __sanitizer_sigaction* act, + __sanitizer_sigaction* oldact) { + SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signum, act, oldact); + }(signum, act, oldact); + + if (act) { + if (ret == 0 && SetSignalHandlerFromSanitizer(signum, false)) { + // If the user sets a signal handler, it becomes uncloaked, even if they + // reuse a sanitizer's signal handler. + + if (oldact) + oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); + } + } else if (ret == 0 && oldact && IsSignalHandlerFromSanitizer(signum)) { + oldact->handler = reinterpret_cast<__sanitizer_sighandler_ptr>(sig_dfl); + } + + return ret; } #define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction_symname) diff --git a/compiler-rt/test/asan/TestCases/wcscat.cpp b/compiler-rt/test/asan/TestCases/wcscat.cpp index fd0b5a4..beab1dc 100644 --- a/compiler-rt/test/asan/TestCases/wcscat.cpp +++ b/compiler-rt/test/asan/TestCases/wcscat.cpp @@ -9,11 +9,13 @@ int main() { const wchar_t *start = L"X means "; const wchar_t *append = L"dog"; - wchar_t goodDst[12]; + wchar_t goodArray[12]; + wchar_t *volatile goodDst = goodArray; wcscpy(goodDst, start); wcscat(goodDst, append); - wchar_t badDst[9]; + wchar_t badArray[9]; + wchar_t *volatile badDst = badArray; wcscpy(badDst, start); fprintf(stderr, "Good so far.\n"); // CHECK-DAG: Good so far. diff --git a/compiler-rt/test/asan/TestCases/wcscpy.cpp b/compiler-rt/test/asan/TestCases/wcscpy.cpp index 8133a58..2b82803 100644 --- a/compiler-rt/test/asan/TestCases/wcscpy.cpp +++ b/compiler-rt/test/asan/TestCases/wcscpy.cpp @@ -8,10 +8,12 @@ int main() { const wchar_t *src = L"X means dog"; - wchar_t goodDst[12]; + wchar_t goodArray[12]; + wchar_t *volatile goodDst = goodArray; wcscpy(goodDst, src); - wchar_t badDst[7]; + wchar_t badArray[7]; + wchar_t *volatile badDst = badArray; fprintf(stderr, "Good so far.\n"); // CHECK-DAG: Good so far. fflush(stderr); diff --git a/compiler-rt/test/asan/TestCases/wcsncat.cpp b/compiler-rt/test/asan/TestCases/wcsncat.cpp index 365e732..04cdcf2 100644 --- a/compiler-rt/test/asan/TestCases/wcsncat.cpp +++ b/compiler-rt/test/asan/TestCases/wcsncat.cpp @@ -9,11 +9,13 @@ int main() { const wchar_t *start = L"X means "; const wchar_t *append = L"dog"; - wchar_t goodDst[15]; + wchar_t goodArray[15]; + wchar_t *volatile goodDst = goodArray; wcscpy(goodDst, start); wcsncat(goodDst, append, 5); - wchar_t badDst[11]; + wchar_t badArray[11]; + wchar_t *volatile badDst = badArray; wcscpy(badDst, start); wcsncat(badDst, append, 1); fprintf(stderr, "Good so far.\n"); diff --git a/compiler-rt/test/asan/TestCases/wcsncpy.cpp b/compiler-rt/test/asan/TestCases/wcsncpy.cpp index 485ddc4..9e11b55 100644 --- a/compiler-rt/test/asan/TestCases/wcsncpy.cpp +++ b/compiler-rt/test/asan/TestCases/wcsncpy.cpp @@ -8,10 +8,12 @@ int main() { const wchar_t *src = L"X means dog"; - wchar_t goodDst[12]; + wchar_t goodArray[12]; + wchar_t *volatile goodDst = goodArray; wcsncpy(goodDst, src, 12); - wchar_t badDst[7]; + wchar_t badArray[7]; + wchar_t *volatile badDst = badArray; wcsncpy(badDst, src, 7); // This should still work. fprintf(stderr, "Good so far.\n"); // CHECK-DAG: Good so far. diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp index 1c74015..0c5a922 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cpp @@ -23,6 +23,10 @@ // Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat. // UNSUPPORTED: android && i386-target-arch +// Note: this test case is unusual because it retrieves the original +// (ASan-installed) signal handler; thus, it is incompatible with the +// cloak_sanitizer_signal_handlers runtime option. + #include <signal.h> #include <stdio.h> #include <stdlib.h> diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp new file mode 100644 index 0000000..422e4ab --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_sigaction.cpp @@ -0,0 +1,53 @@ +// UNSUPPORTED: android +// UNSUPPORTED: hwasan + +// RUN: %clangxx -O0 %s -o %t + +// Sanitizer signal handler not installed; custom signal handler installed +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed but overriden by custom signal handler +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=NONDEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed immutably +// N.B. for handle_segv=2 with cloaking off, there is a pre-existing difference +// in signal vs. sigaction: signal effectively cloaks the handler. +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=NONDEFAULT,SANITIZER +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,SANITIZER + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +void handler(int signum, siginfo_t *info, void *context) { + printf("Custom signal handler\n"); + exit(1); +} + +int main(int argc, char *argv[]) { + struct sigaction sa = {0}; + struct sigaction old = {0}; + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = &handler; + sigaction(SIGSEGV, &sa, &old); + + if (reinterpret_cast<void *>(old.sa_sigaction) == SIG_DFL) + printf("Old handler: default\n"); + // DEFAULT: Old handler: default + else + printf("Old handler: non-default\n"); + // NONDEFAULT: Old handler: non-default + + fflush(stdout); + + // Trying to organically segfault by dereferencing a pointer can be tricky + // in builds with assertions. Additionally, some older platforms may SIGBUS + // instead. + raise(SIGSEGV); + // CUSTOM: Custom signal handler + // SANITIZER: Sanitizer:DEADLYSIGNAL + + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp new file mode 100644 index 0000000..48e5475 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/cloak_signal.cpp @@ -0,0 +1,48 @@ +// UNSUPPORTED: android +// UNSUPPORTED: hwasan + +// RUN: %clangxx -O0 %s -o %t + +// Sanitizer signal handler not installed; custom signal handler installed +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=0:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed but overriden by custom signal handler +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=NONDEFAULT,CUSTOM +// RUN: %env_tool_opts=handle_segv=1:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,CUSTOM + +// Sanitizer signal handler installed immutably +// N.B. for handle_segv=2 with cloaking off, there is a pre-existing difference +// in signal vs. sigaction: signal effectively cloaks the handler. +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=false not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,SANITIZER +// RUN: %env_tool_opts=handle_segv=2:cloak_sanitizer_signal_handlers=true not %run %t 2>&1 | FileCheck %s --check-prefixes=DEFAULT,SANITIZER + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +void my_signal_sighandler(int signum) { + printf("Custom signal handler\n"); + exit(1); +} + +int main(int argc, char *argv[]) { + __sighandler_t old = signal(SIGSEGV, &my_signal_sighandler); + if (old == SIG_DFL) + printf("Old handler: default\n"); + // DEFAULT: Old handler: default + else + printf("Old handler: non-default\n"); + // NONDEFAULT: Old handler: non-default + + fflush(stdout); + + // Trying to organically segfault by dereferencing a pointer can be tricky + // in builds with assertions. Additionally, some older platforms may SIGBUS + // instead. + raise(SIGSEGV); + // CUSTOM: Custom signal handler + // SANITIZER: Sanitizer:DEADLYSIGNAL + + return 0; +} |