summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib/scudo/standalone
diff options
context:
space:
mode:
authorMitch Phillips <31459023+hctim@users.noreply.github.com>2019-12-13 09:09:34 -0800
committerMitch Phillips <31459023+hctim@users.noreply.github.com>2019-12-13 09:09:41 -0800
commited4618edb35688567fcf107785776e27028f4062 (patch)
tree8e54d6312c0a2f3b5171f90c7b6a9a9ff23a0ec8 /compiler-rt/lib/scudo/standalone
parentc1ef116cd99cfcce27a073d4d240b0377c0c62d9 (diff)
downloadbcm5719-llvm-ed4618edb35688567fcf107785776e27028f4062.tar.gz
bcm5719-llvm-ed4618edb35688567fcf107785776e27028f4062.zip
[Scudo] [GWP-ASan] Add GWP-ASan to Scudo Standalone.
Summary: Adds GWP-ASan to Scudo standalone. Default parameters are pulled across from the GWP-ASan build. No backtrace support as of yet. Reviewers: cryptoad, eugenis, pcc Reviewed By: cryptoad Subscribers: merge_guards_bot, mgorny, #sanitizers, llvm-commits, cferris, vlad.tsyrklevich, pcc Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D71229
Diffstat (limited to 'compiler-rt/lib/scudo/standalone')
-rw-r--r--compiler-rt/lib/scudo/standalone/CMakeLists.txt10
-rw-r--r--compiler-rt/lib/scudo/standalone/combined.h63
-rw-r--r--compiler-rt/lib/scudo/standalone/flags.cpp15
-rw-r--r--compiler-rt/lib/scudo/standalone/flags.h8
-rw-r--r--compiler-rt/lib/scudo/standalone/flags_parser.h2
-rw-r--r--compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt8
-rw-r--r--compiler-rt/lib/scudo/standalone/tests/flags_test.cpp17
7 files changed, 122 insertions, 1 deletions
diff --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt
index 08a093ce69f..6b3532b9d6b 100644
--- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt
@@ -1,4 +1,5 @@
add_compiler_rt_component(scudo_standalone)
+add_dependencies(scudo_standalone gwp_asan)
include_directories(../..)
@@ -101,6 +102,13 @@ set(SCUDO_SOURCES_CXX_WRAPPERS
wrappers_cpp.cpp
)
+set(SCUDO_OBJECT_LIBS)
+
+if (COMPILER_RT_HAS_GWP_ASAN)
+ list(APPEND SCUDO_OBJECT_LIBS RTGwpAsan)
+ list(APPEND SCUDO_CFLAGS -DGWP_ASAN_HOOKS)
+endif()
+
if(COMPILER_RT_HAS_SCUDO_STANDALONE)
add_compiler_rt_object_libraries(RTScudoStandalone
ARCHS ${SCUDO_STANDALONE_SUPPORTED_ARCH}
@@ -124,6 +132,7 @@ if(COMPILER_RT_HAS_SCUDO_STANDALONE)
SOURCES ${SCUDO_SOURCES} ${SCUDO_SOURCES_C_WRAPPERS}
ADDITIONAL_HEADERS ${SCUDO_HEADERS}
CFLAGS ${SCUDO_CFLAGS}
+ OBJECT_LIBS ${SCUDO_OBJECT_LIBS}
PARENT_TARGET scudo_standalone)
add_compiler_rt_runtime(clang_rt.scudo_standalone_cxx
STATIC
@@ -131,6 +140,7 @@ if(COMPILER_RT_HAS_SCUDO_STANDALONE)
SOURCES ${SCUDO_SOURCES_CXX_WRAPPERS}
ADDITIONAL_HEADERS ${SCUDO_HEADERS}
CFLAGS ${SCUDO_CFLAGS}
+ OBJECT_LIBS ${SCUDO_OBJECT_LIBS}
PARENT_TARGET scudo_standalone)
add_subdirectory(benchmarks)
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 53e0bf7d730..864436de547 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -18,8 +18,19 @@
#include "quarantine.h"
#include "report.h"
#include "secondary.h"
+#include "string_utils.h"
#include "tsd.h"
+#ifdef GWP_ASAN_HOOKS
+# include "gwp_asan/guarded_pool_allocator.h"
+// GWP-ASan is declared here in order to avoid indirect call overhead. It's also
+// instantiated outside of the Allocator class, as the allocator is only
+// zero-initialised. GWP-ASan requires constant initialisation, and the Scudo
+// allocator doesn't have a constexpr constructor (see discussion here:
+// https://reviews.llvm.org/D69265#inline-624315).
+static gwp_asan::GuardedPoolAllocator GuardedAlloc;
+#endif // GWP_ASAN_HOOKS
+
namespace scudo {
template <class Params> class Allocator {
@@ -133,6 +144,22 @@ public:
Quarantine.init(
static_cast<uptr>(getFlags()->quarantine_size_kb << 10),
static_cast<uptr>(getFlags()->thread_local_quarantine_size_kb << 10));
+
+#ifdef GWP_ASAN_HOOKS
+ gwp_asan::options::Options Opt;
+ Opt.Enabled = getFlags()->GWP_ASAN_Enabled;
+ // Bear in mind - Scudo has its own alignment guarantees that are strictly
+ // enforced. Scudo exposes the same allocation function for everything from
+ // malloc() to posix_memalign, so in general this flag goes unused, as Scudo
+ // will always ask GWP-ASan for an aligned amount of bytes.
+ Opt.PerfectlyRightAlign = getFlags()->GWP_ASAN_PerfectlyRightAlign;
+ Opt.MaxSimultaneousAllocations =
+ getFlags()->GWP_ASAN_MaxSimultaneousAllocations;
+ Opt.SampleRate = getFlags()->GWP_ASAN_SampleRate;
+ Opt.InstallSignalHandlers = getFlags()->GWP_ASAN_InstallSignalHandlers;
+ Opt.Printf = Printf;
+ GuardedAlloc.init(Opt);
+#endif // GWP_ASAN_HOOKS
}
void reset() { memset(this, 0, sizeof(*this)); }
@@ -164,6 +191,14 @@ public:
uptr Alignment = MinAlignment,
bool ZeroContents = false) {
initThreadMaybe();
+
+#ifdef GWP_ASAN_HOOKS
+ if (UNLIKELY(GuardedAlloc.shouldSample())) {
+ if (void *Ptr = GuardedAlloc.allocate(roundUpTo(Size, Alignment)))
+ return Ptr;
+ }
+#endif // GWP_ASAN_HOOKS
+
ZeroContents |= static_cast<bool>(Options.ZeroContents);
if (UNLIKELY(Alignment > MaxAlignment)) {
@@ -261,6 +296,13 @@ public:
// being destroyed properly. Any other heap operation will do a full init.
initThreadMaybe(/*MinimalInit=*/true);
+#ifdef GWP_ASAN_HOOKS
+ if (UNLIKELY(GuardedAlloc.pointerIsMine(Ptr))) {
+ GuardedAlloc.deallocate(Ptr);
+ return;
+ }
+#endif // GWP_ASAN_HOOKS
+
if (&__scudo_deallocate_hook)
__scudo_deallocate_hook(Ptr);
@@ -300,6 +342,17 @@ public:
DCHECK_NE(OldPtr, nullptr);
DCHECK_NE(NewSize, 0);
+#ifdef GWP_ASAN_HOOKS
+ if (UNLIKELY(GuardedAlloc.pointerIsMine(OldPtr))) {
+ uptr OldSize = GuardedAlloc.getSize(OldPtr);
+ void *NewPtr = allocate(NewSize, Chunk::Origin::Malloc, Alignment);
+ if (NewPtr)
+ memcpy(NewPtr, OldPtr, (NewSize < OldSize) ? NewSize : OldSize);
+ GuardedAlloc.deallocate(OldPtr);
+ return NewPtr;
+ }
+#endif // GWP_ASAN_HOOKS
+
if (UNLIKELY(!isAligned(reinterpret_cast<uptr>(OldPtr), MinAlignment)))
reportMisalignedPointer(AllocatorAction::Reallocating, OldPtr);
@@ -446,6 +499,12 @@ public:
initThreadMaybe();
if (UNLIKELY(!Ptr))
return 0;
+
+#ifdef GWP_ASAN_HOOKS
+ if (UNLIKELY(GuardedAlloc.pointerIsMine(Ptr)))
+ return GuardedAlloc.getSize(Ptr);
+#endif // GWP_ASAN_HOOKS
+
Chunk::UnpackedHeader Header;
Chunk::loadHeader(Cookie, Ptr, &Header);
// Getting the usable size of a chunk only makes sense if it's allocated.
@@ -464,6 +523,10 @@ public:
// A corrupted chunk will not be reported as owned, which is WAI.
bool isOwned(const void *Ptr) {
initThreadMaybe();
+#ifdef GWP_ASAN_HOOKS
+ if (GuardedAlloc.pointerIsMine(Ptr))
+ return true;
+#endif // GWP_ASAN_HOOKS
if (!Ptr || !isAligned(reinterpret_cast<uptr>(Ptr), MinAlignment))
return false;
Chunk::UnpackedHeader Header;
diff --git a/compiler-rt/lib/scudo/standalone/flags.cpp b/compiler-rt/lib/scudo/standalone/flags.cpp
index 1e970ae4950..25407899fd4 100644
--- a/compiler-rt/lib/scudo/standalone/flags.cpp
+++ b/compiler-rt/lib/scudo/standalone/flags.cpp
@@ -22,6 +22,13 @@ void Flags::setDefaults() {
#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "flags.inc"
#undef SCUDO_FLAG
+
+#ifdef GWP_ASAN_HOOKS
+#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
+ GWP_ASAN_##Name = DefaultValue;
+#include "gwp_asan/options.inc"
+#undef GWP_ASAN_OPTION
+#endif // GWP_ASAN_HOOKS
}
void registerFlags(FlagParser *Parser, Flags *F) {
@@ -30,6 +37,14 @@ void registerFlags(FlagParser *Parser, Flags *F) {
reinterpret_cast<void *>(&F->Name));
#include "flags.inc"
#undef SCUDO_FLAG
+
+#ifdef GWP_ASAN_HOOKS
+#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
+ Parser->registerFlag("GWP_ASAN_"#Name, Description, FlagType::FT_##Type, \
+ reinterpret_cast<void *>(&F->GWP_ASAN_##Name));
+#include "gwp_asan/options.inc"
+#undef GWP_ASAN_OPTION
+#endif // GWP_ASAN_HOOKS
}
static const char *getCompileDefinitionScudoDefaultOptions() {
diff --git a/compiler-rt/lib/scudo/standalone/flags.h b/compiler-rt/lib/scudo/standalone/flags.h
index edd39a1b8ba..2cd0a5b1334 100644
--- a/compiler-rt/lib/scudo/standalone/flags.h
+++ b/compiler-rt/lib/scudo/standalone/flags.h
@@ -17,6 +17,14 @@ struct Flags {
#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Type Name;
#include "flags.inc"
#undef SCUDO_FLAG
+
+#ifdef GWP_ASAN_HOOKS
+#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
+ Type GWP_ASAN_##Name;
+#include "gwp_asan/options.inc"
+#undef GWP_ASAN_OPTION
+#endif // GWP_ASAN_HOOKS
+
void setDefaults();
};
diff --git a/compiler-rt/lib/scudo/standalone/flags_parser.h b/compiler-rt/lib/scudo/standalone/flags_parser.h
index 857b50e880e..32511f768c6 100644
--- a/compiler-rt/lib/scudo/standalone/flags_parser.h
+++ b/compiler-rt/lib/scudo/standalone/flags_parser.h
@@ -29,7 +29,7 @@ public:
void printFlagDescriptions();
private:
- static const u32 MaxFlags = 12;
+ static const u32 MaxFlags = 16;
struct Flag {
const char *Name;
const char *Desc;
diff --git a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
index f1f9400ff95..470f89df022 100644
--- a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
@@ -20,6 +20,10 @@ if(ANDROID)
list(APPEND SCUDO_UNITTEST_CFLAGS -fno-emulated-tls)
endif()
+if (COMPILER_RT_HAS_GWP_ASAN)
+ list(APPEND SCUDO_UNITTEST_CFLAGS -DGWP_ASAN_HOOKS)
+endif()
+
set(SCUDO_TEST_ARCH ${SCUDO_STANDALONE_SUPPORTED_ARCH})
# gtests requires c++
@@ -38,6 +42,10 @@ endforeach()
macro(add_scudo_unittest testname)
cmake_parse_arguments(TEST "" "" "SOURCES;ADDITIONAL_RTOBJECTS" ${ARGN})
+ if (COMPILER_RT_HAS_GWP_ASAN)
+ list(APPEND TEST_ADDITIONAL_RTOBJECTS RTGwpAsan)
+ endif()
+
if(COMPILER_RT_HAS_SCUDO_STANDALONE)
foreach(arch ${SCUDO_TEST_ARCH})
# Additional runtime objects get added along RTScudoStandalone
diff --git a/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp b/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp
index 45918ad4d2c..85ae422e70f 100644
--- a/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp
@@ -117,3 +117,20 @@ TEST(ScudoFlagsTest, AllocatorFlags) {
EXPECT_TRUE(Flags.delete_size_mismatch);
EXPECT_EQ(2048, Flags.quarantine_max_chunk_size);
}
+
+TEST(ScudoFlagsTest, GWPASanFlags) {
+#ifndef GWP_ASAN_HOOKS
+ GTEST_SKIP() << "GWP-ASan wasn't built as part of Scudo Standalone.";
+#endif // GWP_ASAN_HOOKS
+
+ scudo::FlagParser Parser;
+ scudo::Flags Flags;
+ scudo::registerFlags(&Parser, &Flags);
+ Flags.setDefaults();
+ Flags.GWP_ASAN_Enabled = false;
+ Parser.parseString("GWP_ASAN_Enabled=true:GWP_ASAN_SampleRate=1:"
+ "GWP_ASAN_InstallSignalHandlers=false");
+ EXPECT_TRUE(Flags.GWP_ASAN_Enabled);
+ EXPECT_FALSE(Flags.GWP_ASAN_InstallSignalHandlers);
+ EXPECT_EQ(1, Flags.GWP_ASAN_SampleRate);
+}
OpenPOWER on IntegriCloud