Unpoison stack memory before deallocation
authorMarcus Holland-Moritz <mhx@fb.com>
Wed, 4 May 2016 10:28:44 +0000 (03:28 -0700)
committerFacebook Github Bot 4 <facebook-github-bot-4-bot@fb.com>
Wed, 4 May 2016 10:35:21 +0000 (03:35 -0700)
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
folly/experimental/fibers/FiberManager.cpp
folly/experimental/fibers/FiberManager.h

index 5dc2ff221f3875cb63f6bfebcb40afcbd7d32ceb..67ea620dc30e2a2fdbff0afd3f789c3b1e4b2acb 100644 (file)
@@ -111,6 +111,9 @@ void Fiber::init(bool recordStackUsed) {
 }
 
 Fiber::~Fiber() {
+#ifdef FOLLY_SANITIZE_ADDRESS
+  fiberManager_.unpoisonFiberStack(this);
+#endif
   fiberManager_.stackAllocator_.deallocate(
       static_cast<unsigned char*>(fcontext_.stackLimit()),
       fiberManager_.options_.stackSize);
index b23f4434326530048d22ea3821b314c4e96146ad..7723953761fd7b91b5e7255cab10fd15e2ea86e6 100644 (file)
@@ -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
 }
 }
index 559f70e79f799bcc1e21e2cc60169718e8ed75dd..405b2d199118a93622451b94acc50a91cba1c60b 100644 (file)
@@ -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
 };