From 6959fbe7b9ac7591a51c4b15f5cb6b3df8ca8016 Mon Sep 17 00:00:00 2001 From: Marcus Holland-Moritz Date: Wed, 4 May 2016 03:28:44 -0700 Subject: [PATCH] Unpoison stack memory before deallocation Summary: This is a workaround (maybe even the correct fix if it turns out that ASan can't detect this FP case) for the problem described in https://llvm.org/bugs/show_bug.cgi?id=27627 where a memory region previously allocated by a fiber stack can overlap with the region of an mmap'd file. Accessing parts of the mmap'd file close to the stack region will trigger a false positive ASan error. This change makes sure each fiber explicitly unpoisons its stack memory by calling __asan_unpoison_memory_region in an ASan-enabled build. Reviewed By: yhfung Differential Revision: D3257924 fb-gh-sync-id: 484062e80af67dfd39d2eaf3cbb52fa3483924eb fbshipit-source-id: 484062e80af67dfd39d2eaf3cbb52fa3483924eb --- folly/experimental/fibers/Fiber.cpp | 3 ++ folly/experimental/fibers/FiberManager.cpp | 39 +++++++++++++++++++++- folly/experimental/fibers/FiberManager.h | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/folly/experimental/fibers/Fiber.cpp b/folly/experimental/fibers/Fiber.cpp index 5dc2ff22..67ea620d 100644 --- a/folly/experimental/fibers/Fiber.cpp +++ b/folly/experimental/fibers/Fiber.cpp @@ -111,6 +111,9 @@ void Fiber::init(bool recordStackUsed) { } Fiber::~Fiber() { +#ifdef FOLLY_SANITIZE_ADDRESS + fiberManager_.unpoisonFiberStack(this); +#endif fiberManager_.stackAllocator_.deallocate( static_cast(fcontext_.stackLimit()), fiberManager_.options_.stackSize); diff --git a/folly/experimental/fibers/FiberManager.cpp b/folly/experimental/fibers/FiberManager.cpp index b23f4434..77239537 100644 --- a/folly/experimental/fibers/FiberManager.cpp +++ b/folly/experimental/fibers/FiberManager.cpp @@ -36,15 +36,22 @@ static void __asan_enter_fiber_weak( __attribute__((__weakref__("__asan_enter_fiber"))); static void __asan_exit_fiber_weak() __attribute__((__weakref__("__asan_exit_fiber"))); +static void __asan_unpoison_memory_region_weak( + void const /* nolint */ volatile* addr, + size_t size) __attribute__((__weakref__("__asan_unpoison_memory_region"))); typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t); typedef void (*AsanExitFiberFuncPtr)(); +typedef void (*AsanUnpoisonMemoryRegionFuncPtr)( + void const /* nolint */ volatile*, + size_t); namespace folly { namespace fibers { static AsanEnterFiberFuncPtr getEnterFiberFunc(); static AsanExitFiberFuncPtr getExitFiberFunc(); +static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc(); } } @@ -199,6 +206,18 @@ void FiberManager::registerFiberDeactivationWithAsan(Fiber* fiber) { } } +void FiberManager::unpoisonFiberStack(const Fiber* fiber) { + auto stack = fiber->getStack(); + + // Check if we can find a fiber enter function and call it if we find one + static AsanUnpoisonMemoryRegionFuncPtr fn = getUnpoisonMemoryRegionFunc(); + if (fn == nullptr) { + LOG(FATAL) << "This version of ASAN doesn't support memory unpoisoning"; + } else { + fn(stack.first, stack.second); + } +} + static AsanEnterFiberFuncPtr getEnterFiberFunc() { AsanEnterFiberFuncPtr fn{nullptr}; @@ -225,7 +244,7 @@ static AsanExitFiberFuncPtr getExitFiberFunc() { return fn; } - // Check whether we can find a dynamically linked enter function + // Check whether we can find a dynamically linked exit function if (nullptr != (fn = (AsanExitFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_exit_fiber"))) { return fn; @@ -235,6 +254,24 @@ static AsanExitFiberFuncPtr getExitFiberFunc() { return nullptr; } +static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc() { + AsanUnpoisonMemoryRegionFuncPtr fn{nullptr}; + + // Check whether weak reference points to statically linked unpoison function + if (nullptr != (fn = &::__asan_unpoison_memory_region_weak)) { + return fn; + } + + // Check whether we can find a dynamically linked unpoison function + if (nullptr != (fn = (AsanUnpoisonMemoryRegionFuncPtr)dlsym( + RTLD_DEFAULT, "__asan_unpoison_memory_region"))) { + return fn; + } + + // Couldn't find the function at all + return nullptr; +} + #endif // FOLLY_SANITIZE_ADDRESS } } diff --git a/folly/experimental/fibers/FiberManager.h b/folly/experimental/fibers/FiberManager.h index 559f70e7..405b2d19 100644 --- a/folly/experimental/fibers/FiberManager.h +++ b/folly/experimental/fibers/FiberManager.h @@ -464,6 +464,7 @@ class FiberManager : public ::folly::Executor { void registerFiberActivationWithAsan(Fiber* fiber); void registerFiberDeactivationWithAsan(Fiber* fiber); + void unpoisonFiberStack(const Fiber* fiber); #endif // FOLLY_SANITIZE_ADDRESS }; -- 2.34.1