[compiler-rt] a683abe - [Scudo] Use GWP-ASan's aligned allocations and fixup postalloc hooks.
Mitch Phillips via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 23 10:07:52 PDT 2021
Author: Mitch Phillips
Date: 2021-04-23T10:07:36-07:00
New Revision: a683abe5c026cffff12a943564f4cb1b20972abf
URL: https://github.com/llvm/llvm-project/commit/a683abe5c026cffff12a943564f4cb1b20972abf
DIFF: https://github.com/llvm/llvm-project/commit/a683abe5c026cffff12a943564f4cb1b20972abf.diff
LOG: [Scudo] Use GWP-ASan's aligned allocations and fixup postalloc hooks.
This patch does a few cleanup things:
1. The non-standalone scudo has a problem where GWP-ASan allocations
may not meet alignment requirements where Scudo was requested to have
alignment >= 16. Use the new GWP-ASan API to fix this.
2. The standalone variant loses some debugging information inside of
GWP-ASan because we ask GWP-ASan to allocate an aligned size in the
frontend. This means reports end up with 'UaF on a 16-byte allocation'
for a 1-byte allocation with 16-byte alignment. Also use the new API to
fix this.
3. Add post-alloc hooks for GWP-ASan intercepted allocations, and add
stats tracking for GWP-ASan allocations.
4. Add a small test that checks the alignment of the frontend
allocator, so that it can be used under GWP-ASan torture mode.
5. Add GWP-ASan torture mode as a testing configuration to catch these
regressions.
Depends on D94830, D95889.
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D95884
Added:
compiler-rt/test/scudo/standalone/unit/gwp_asan/lit.site.cfg.py.in
Modified:
compiler-rt/lib/scudo/scudo_allocator.cpp
compiler-rt/lib/scudo/standalone/combined.h
compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
compiler-rt/test/scudo/standalone/CMakeLists.txt
Removed:
################################################################################
diff --git a/compiler-rt/lib/scudo/scudo_allocator.cpp b/compiler-rt/lib/scudo/scudo_allocator.cpp
index 82864405dfb05..d8a9a9cc5f90b 100644
--- a/compiler-rt/lib/scudo/scudo_allocator.cpp
+++ b/compiler-rt/lib/scudo/scudo_allocator.cpp
@@ -303,13 +303,6 @@ struct Allocator {
bool ForceZeroContents = false) {
initThreadMaybe();
-#ifdef GWP_ASAN_HOOKS
- if (UNLIKELY(GuardedAlloc.shouldSample())) {
- if (void *Ptr = GuardedAlloc.allocate(Size))
- return Ptr;
- }
-#endif // GWP_ASAN_HOOKS
-
if (UNLIKELY(Alignment > MaxAlignment)) {
if (AllocatorMayReturnNull())
return nullptr;
@@ -318,6 +311,16 @@ struct Allocator {
if (UNLIKELY(Alignment < MinAlignment))
Alignment = MinAlignment;
+#ifdef GWP_ASAN_HOOKS
+ if (UNLIKELY(GuardedAlloc.shouldSample())) {
+ if (void *Ptr = GuardedAlloc.allocate(Size, Alignment)) {
+ if (SCUDO_CAN_USE_HOOKS && &__sanitizer_malloc_hook)
+ __sanitizer_malloc_hook(Ptr, Size);
+ return Ptr;
+ }
+ }
+#endif // GWP_ASAN_HOOKS
+
const uptr NeededSize = RoundUpTo(Size ? Size : 1, MinAlignment) +
Chunk::getHeaderSize();
const uptr AlignedSize = (Alignment > MinAlignment) ?
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 6d68d6dc6c6ca..7ae6086dd8f15 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -290,27 +290,31 @@ class Allocator {
bool ZeroContents = false) {
initThreadMaybe();
+ const Options Options = Primary.Options.load();
+ if (UNLIKELY(Alignment > MaxAlignment)) {
+ if (Options.get(OptionBit::MayReturnNull))
+ return nullptr;
+ reportAlignmentTooBig(Alignment, MaxAlignment);
+ }
+ if (Alignment < MinAlignment)
+ Alignment = MinAlignment;
+
#ifdef GWP_ASAN_HOOKS
if (UNLIKELY(GuardedAlloc.shouldSample())) {
- if (void *Ptr = GuardedAlloc.allocate(roundUpTo(Size, Alignment)))
+ if (void *Ptr = GuardedAlloc.allocate(Size, Alignment)) {
+ if (UNLIKELY(&__scudo_allocate_hook))
+ __scudo_allocate_hook(Ptr, Size);
+ Stats.add(StatAllocated, Size);
return Ptr;
+ }
}
#endif // GWP_ASAN_HOOKS
- const Options Options = Primary.Options.load();
const FillContentsMode FillContents = ZeroContents ? ZeroFill
: TSDRegistry.getDisableMemInit()
? NoFill
: Options.getFillContentsMode();
- if (UNLIKELY(Alignment > MaxAlignment)) {
- if (Options.get(OptionBit::MayReturnNull))
- return nullptr;
- reportAlignmentTooBig(Alignment, MaxAlignment);
- }
- if (Alignment < MinAlignment)
- Alignment = MinAlignment;
-
// If the requested size happens to be 0 (more common than you might think),
// allocate MinAlignment bytes on top of the header. Then add the extra
// bytes required to fulfill the alignment requirements: we allocate enough
@@ -503,18 +507,20 @@ class Allocator {
// being destroyed properly. Any other heap operation will do a full init.
initThreadMaybe(/*MinimalInit=*/true);
+ if (UNLIKELY(&__scudo_deallocate_hook))
+ __scudo_deallocate_hook(Ptr);
+
+ if (UNLIKELY(!Ptr))
+ return;
+
#ifdef GWP_ASAN_HOOKS
if (UNLIKELY(GuardedAlloc.pointerIsMine(Ptr))) {
GuardedAlloc.deallocate(Ptr);
+ Stats.add(StatFree, GuardedAlloc.getSize(Ptr));
return;
}
#endif // GWP_ASAN_HOOKS
- if (UNLIKELY(&__scudo_deallocate_hook))
- __scudo_deallocate_hook(Ptr);
-
- if (UNLIKELY(!Ptr))
- return;
if (UNLIKELY(!isAligned(reinterpret_cast<uptr>(Ptr), MinAlignment)))
reportMisalignedPointer(AllocatorAction::Deallocating, Ptr);
@@ -571,6 +577,7 @@ class Allocator {
if (NewPtr)
memcpy(NewPtr, OldPtr, (NewSize < OldSize) ? NewSize : OldSize);
GuardedAlloc.deallocate(OldPtr);
+ Stats.add(StatFree, OldSize);
return NewPtr;
}
#endif // GWP_ASAN_HOOKS
diff --git a/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp b/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
index e8872a154fc1e..eed8f0319337b 100644
--- a/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
@@ -94,6 +94,18 @@ TEST(ScudoWrappersCTest, Calloc) {
EXPECT_EQ(errno, ENOMEM);
}
+TEST(ScudoWrappersCTest, SmallAlign) {
+ void *P;
+ for (size_t Size = 1; Size <= 0x10000; Size <<= 1) {
+ for (size_t Align = 1; Align <= 0x10000; Align <<= 1) {
+ for (size_t Count = 0; Count < 3; ++Count) {
+ P = memalign(Align, Size);
+ EXPECT_TRUE(reinterpret_cast<uintptr_t>(P) % Align == 0);
+ }
+ }
+ }
+}
+
TEST(ScudoWrappersCTest, Memalign) {
void *P;
for (size_t I = FIRST_32_SECOND_64(2U, 3U); I <= 18U; I++) {
diff --git a/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp b/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
index d24b6651d95e3..9df06dcdf1420 100644
--- a/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
@@ -66,6 +66,10 @@ class Pixel {
};
TEST(ScudoWrappersCppTest, New) {
+ if (getenv("SKIP_TYPE_MISMATCH")) {
+ printf("Skipped type mismatch tests.\n");
+ return;
+ }
testCxxNew<bool>();
testCxxNew<uint8_t>();
testCxxNew<uint16_t>();
diff --git a/compiler-rt/test/scudo/standalone/CMakeLists.txt b/compiler-rt/test/scudo/standalone/CMakeLists.txt
index a55fc6b5daa50..3452398a65b5f 100644
--- a/compiler-rt/test/scudo/standalone/CMakeLists.txt
+++ b/compiler-rt/test/scudo/standalone/CMakeLists.txt
@@ -4,6 +4,12 @@ if(COMPILER_RT_INCLUDE_TESTS AND COMPILER_RT_HAS_SCUDO_STANDALONE)
${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg.py)
list(APPEND SCUDO_STANDALONE_TEST_DEPS ScudoUnitTests)
list(APPEND SCUDO_STANDALONE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit)
+ if (COMPILER_RT_HAS_GWP_ASAN)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/unit/gwp_asan/lit.site.cfg.py.in
+ ${CMAKE_CURRENT_BINARY_DIR}/unit/gwp_asan/lit.site.cfg.py)
+ list(APPEND SCUDO_STANDALONE_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/unit/gwp_asan)
+ endif()
endif()
add_lit_testsuite(check-scudo_standalone
diff --git a/compiler-rt/test/scudo/standalone/unit/gwp_asan/lit.site.cfg.py.in b/compiler-rt/test/scudo/standalone/unit/gwp_asan/lit.site.cfg.py.in
new file mode 100644
index 0000000000000..c12b72c009b2e
--- /dev/null
+++ b/compiler-rt/test/scudo/standalone/unit/gwp_asan/lit.site.cfg.py.in
@@ -0,0 +1,24 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+
+# Setup config name.
+config.name = 'ScudoStandalone-Unit-GwpAsanTorture'
+
+# Setup test source and exec root.
+# For unit tests, we define it as build directory with unit tests.
+config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/scudo/standalone/tests"
+config.test_source_root = config.test_exec_root
+
+# This is a second run of the Scudo test suite, but this time under a "torture"
+# GWP-ASan mode. Every allocation that can go to GWP-ASan, should go to
+# GWP-ASan. This ensures that GWP-ASan allocations meet the same testing
+# requirements as the native Scudo allocations. Reserves 409MiB of vaddr space
+# for the guarded pool, and this should be paged in on demand. If necessary (for
+# 32-bit or places where kernel commits immediately), this could possibly be
+# reduced.
+config.environment['SCUDO_OPTIONS'] = 'GWP_ASAN_SampleRate=1:GWP_ASAN_MaxSimultaneousAllocations=100000'
+
+# GWP-ASan doesn't support malloc-type mismatch.
+config.environment['SKIP_TYPE_MISMATCH'] = '1'
More information about the llvm-commits
mailing list